MRaster lib 21.0.0.0
Image Processing Library
Loading...
Searching...
No Matches
ramCanvasTpl.hpp
Go to the documentation of this file.
1// -*- Mode:C++; Coding:us-ascii-unix; fill-column:158 -*-
2/*******************************************************************************************************************************************************.H.S.**/
3/**
4 @file ramCanvasTpl.hpp
5 @author Mitch Richling <https://www.mitchr.me>
6 @brief Internal include file for ramCanvas types.@EOL
7 @copyright
8 @parblock
9 Copyright (c) 1988-2015, Mitchell Jay Richling <https://www.mitchr.me> All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
12
13 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
14
15 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17
18 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software
19 without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGE.
27 @endparblock
28 @filedetails
29 Note that this file is not intended for inclusion into end user application code; however, this use is quite possible in some special cases. For a less
30 complex interface, one is encouraged to include the ramCanvas.h include file instead.
31*/
32/*******************************************************************************************************************************************************.H.E.**/
33
34#ifndef MJR_INCLUDE_ramCanvasTpl
35
36////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
37#include "MRcolor.hpp"
38#include "hersheyFont.hpp"
39#include "MRpoint2d.hpp"
40
41////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
42#ifdef MRASTER_FOUND_TIFF
43#include <unistd.h> /* UNIX std stf POSIX */
44#include <tiffio.h> /* libTIFF libTIFF */
45#endif
46
47////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
48#include <algorithm> /* STL algorithm C++11 */
49#include <chrono> /* time C++11 */
50#include <cmath> /* std:: C math.h C++11 */
51#include <complex> /* Complex Numbers C++11 */
52#include <cstdint> /* std:: C stdint.h C++11 */
53#include <fstream> /* C++ fstream C++98 */
54#include <functional> /* STL funcs C++98 */
55#include <iomanip> /* C++ stream formatting C++11 */
56#include <iostream> /* C++ iostream C++11 */
57#include <iterator> /* STL Iterators C++11 */
58#include <list> /* STL list C++11 */
59#include <map> /* STL map C++11 */
60#include <numbers> /* C++ math constants C++20 */
61#include <random> /* C++ random numbers C++11 */
62#include <sstream> /* C++ string stream C++ */
63#include <stdexcept> /* Exceptions C++11 */
64#include <string> /* C++ strings C++11 */
65#include <type_traits> /* C++ metaprogramming C++11 */
66#include <utility> /* STL Misc Utilities C++11 */
67#include <vector> /* STL vector C++11 */
68
69////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70// Put everything in the mjr namespace
71namespace mjr {
72 /** @brief Class providing off-screen drawing functionality.@EOL
73
74 This class essentially manages a 2D array of pixels (represented as colorTpl objects). Both integer and floating point coordinates are supported.
75
76 Coordinates
77 ===========
78
79 Traditional Mathematical Coordinate System
80 ------------------------------------------
81
82 The traditional coordinate system used in mathematics is the Cartesian Coordinate system. In this system the axes represent real numbers which increase as
83 one moves to the right or up.
84
85
86 ^ y (increasing upward)
87 |
88 . (0, 1)
89 |
90 |
91 |
92 (-1,0) | (0,0) x (increasing to the right)
93 <-.--------+--------.----->
94 | (1,0)
95 |
96 |
97 |
98 . (0, -1)
99 |
100 v
101
102 Traditional Computer Graphics Coordinate System
103 -----------------------------------------------
104
105 Unlike the Cartesian coordinate system, the traditional coordinates used in computer graphics have only positive, integer coordinates, the origin at the upper
106 left, and the x and y coordinates increasing to the right and down. This is a very natural choice given the discrete nature of digital displays and the
107 typical layout of 2D arrays in RAM.
108
109
110 (0,0) +------------+ (numPixX-1, 0)
111 | |
112 | |
113 | |
114 | |
115 | |
116 (numPixY-1, 0) +------------+ (numPixX-1, numPixY-1)
117
118 ramCanvas Coordinate Systems
119 ----------------------------
120
121 This library supports two sets of coordinates for each image:
122
123 - Integer -- much like traditional computer graphics coordinates
124
125 - Floating Point -- much like mathematical coordinates
126
127 The integer coordinates are a generalization of the traditional integer coordinates used for computer graphics. Like the traditional system, they are
128 unsigned integers (so the coordinates start at 0), each pixel is one unit from the previous, and the maximum pixel coordinate is one minus the canvas size in
129 that coordinate direction. The generalization is that the origin of the coordinate system can be any of the four corners. By default the origin is the
130 lower, left corner. Note that the memory layout of the image is not modified by the integer coordinate system -- i.e. the location of the origin is
131 irrelevant when it comes to the layout of bits in RAM. In RAM the layout is the same as the traditional coordinate system where the coordinates are the
132 indexes of the image array. What is the point? The location of the origin is taken into consideration when the image is exported/imported by functions like
133 writeRAWfile.
134
135 @tparam intCrdT An integral type used for the integer image coordinates. Should be signed, and at least @f$ 4\cdot\log_2(\mathtt{numPixX} \cdot \mathtt{numPixY}) @f$ bits in size
136 @tparam colorT A type for the image pixels (a color)
137 @tparam fltCrdT A floating point type used for the floating point image coordinates
138 @tparam enableDrawModes If true, enables drawing modes othe than drawModeType::SET. */
139 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
140 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
142 public:
143
144 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
145 /** @name Handy ramCanvasTpl converter classes. */
146 //@{
147 //--------------------------------------------------------------------------------------------------------------------------------------------------------
148 /** This class is an incomplete rcConverter (no getPxColorNC method) that provides a nice base for homogenious rcConverters. */
149 template<class inRamCanvasT>
151 public:
152 inRamCanvasT& attachedRC;
153 rcConverterHomoBase(inRamCanvasT& aRC) : attachedRC(aRC) { }
154 inline bool isIntAxOrientationNaturalX() { return attachedRC.isIntAxOrientationNaturalX(); }
155 inline bool isIntAxOrientationNaturalY() { return attachedRC.isIntAxOrientationNaturalY(); }
156 inline typename inRamCanvasT::coordIntType getNumPixX() { return attachedRC.getNumPixX(); }
157 inline typename inRamCanvasT::coordIntType getNumPixY() { return attachedRC.getNumPixY(); }
158 };
159 //--------------------------------------------------------------------------------------------------------------------------------------------------------
160 template<class inRamCanvasT>
161 class rcConverterIdentity : public rcConverterHomoBase<inRamCanvasT> {
162 public:
163 rcConverterIdentity(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
164 typedef typename inRamCanvasT::colorType colorType;
165 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y); }
166 };
167 //--------------------------------------------------------------------------------------------------------------------------------------------------------
168 template<class inRamCanvasT>
169 class rcConverterRGBbyte : public rcConverterHomoBase<inRamCanvasT> {
170 public:
171 rcConverterRGBbyte(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
172 typedef typename inRamCanvasT::colorType::colConRGBbyte colorType;
173 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGB_byte(); }
174 };
175 //--------------------------------------------------------------------------------------------------------------------------------------------------------
176 template<class inRamCanvasT>
178 public:
179 rcConverterRGBAbyte(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
180 typedef typename inRamCanvasT::colorType::colConRGBAbyte colorType;
181 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGBA_byte(); }
182 };
183 //--------------------------------------------------------------------------------------------------------------------------------------------------------
184 template<class inRamCanvasT>
186 public:
187 rcConverterRGBdbl(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
188 typedef typename inRamCanvasT::colorType::colConRGBdbl colorType;
189 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGB_dbl(); }
190 };
191 //--------------------------------------------------------------------------------------------------------------------------------------------------------
192 template<class inRamCanvasT>
194 public:
195 rcConverterRGBAdbl(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
196 typedef typename inRamCanvasT::colorType::colConRGBAdbl colorType;
197 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGBA_dbl(); }
198 };
199 //--------------------------------------------------------------------------------------------------------------------------------------------------------
200 /** Colorize a ramCanvasTpl with integer channels using a color scheme. */
201 template<class inRamCanvasT, class outColorT, class colorScheme, bool clamp, int factor, int chan>
202 class rcConverterColorScheme : public rcConverterHomoBase<inRamCanvasT> {
203 public:
204 rcConverterColorScheme(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
205 typedef outColorT colorType;
206 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) {
207 typename outColorT::csIntType csi = static_cast<typename outColorT::csIntType>(rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getChan(chan) * factor);
208 if (clamp)
209 csi = mjr::math::ivl::clamp(csi, colorScheme::numC-1);
210 return colorScheme::c(csi);
211 }
212 };
213 //--------------------------------------------------------------------------------------------------------------------------------------------------------
214 /** Convert a ramCanvasTpl to a greyscale image using colorT::intensity(). */
215 template<class inRamCanvasT, class outColorChanT>
216 class rcConverterMonoIntensity : public rcConverterHomoBase<inRamCanvasT> {
217 public:
218 rcConverterMonoIntensity(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
220 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) {
221 return static_cast<outColorChanT>(rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).intensity());
222 }
223 };
224 //@}
225
226 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
227 /** @name Typedefs related to template parameters */
228 //@{
229 typedef point2d<fltCrdT> pointFltType; //!< Real coordinate pair type
230 typedef point2d<intCrdT> pointIntType; //!< Integer coordinate pair type
231 typedef std::complex<fltCrdT> cplxFltType; //!< Real coordinate complex type (Provided for convince -- not used in ramCanvasTpl)
232 typedef std::complex<intCrdT> cplxIntType; //!< Integer coordinate complex type (Provided for convince -- not used in ramCanvasTpl)
233 typedef intCrdT coordIntType; //!< Integer type for coordinates
234 typedef fltCrdT coordFltType; //!< Real type for coordinates
235 typedef colorT colorType; //!< Color type for pixels
236 //@}
237
238 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
239 /** @name Typedefs related to colorT */
240 //@{
241 typedef typename colorT::channelType colorChanType; //!< colorT: Channel type
242 typedef typename colorT::maskType colorMaskType; //!< colorT: Mask type
243 typedef typename colorT::channelArithDType colorChanArithDType; //!< colorT: Channel arithmatic (Int: -)
244 typedef typename colorT::channelArithSPType colorChanArithSPType; //!< colorT: Channel arithmatic (Int: +*)
245 typedef typename colorT::channelArithSDPType colorChanArithSDPType; //!< colorT: Channel arithmatic (Int: +-*)
246 typedef typename colorT::channelArithFltType colorChanArithFltType; //!< colorT: Channel arithmatic (Flt: +-*)
247 typedef typename colorT::channelArithLogType colorChanArithLogType; //!< colorT: Channel arithmatic (Int: ^|&~)
248 typedef typename colorT::colorSpaceEnum colorSpaceEnum; //!< colorT: Color spaces
249 typedef typename colorT::cornerColorEnum colorCornerEnum; //!< colorT: RGB Color Corners
250 typedef typename colorT::colorArgType colorArgType; //!< colorT: Argument passing type
251 typedef typename colorT::colorPtrType colorPtrType; //!< colorT: Pointer to color
252 typedef typename colorT::colorRefType colorRefType; //!< colorT: Ref to a color
253 typedef typename colorT::colorCRefType colorCRefType; //!< colorT: Const Ref to a color
254 typedef typename colorT::csIntType csIntType; //!< colorT: Color Scheme Integer Type
255 typedef typename colorT::csFltType csFltType; //!< colorT: Color Scheme Float Type
256 typedef typename colorT::csNatType csNatType; //!< colorT: Color Scheme Natural Type
257 typedef typename colorT::cmfInterpolationEnum cmfInterpolationEnum; //!< colorT: Interpolation for color match functions
258 //@}
259
260 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
261 /** @name Iterator Typedefs */
262 //@{
263 typedef colorT* pixelIterator; //!< pixel store iterators
264 typedef colorT* iterator; //!< pixel store iterators
265 //@}
266
267 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
268 /** @name Enumerations */
269 //@{
270 /** Enum for real axis orientation */
271 enum class realAxisOrientation { INVERTED, //!< Real axis is inverted with respect to the integer axis
272 NATURAL //!< Real axis is not inverted with respect to the integer axis
273 };
274
275 /** Enum for integer axis orientation.
276
277 Note integer axis orientation has no impact on the in-ram representation of the image. i.e. Pixel (0,0) will always be the first element of the pixels
278 array. The integer axis orientation is used to arrange the pixels when a canvas is saved/loaded to/from an image file. */
279 enum class intAxisOrientation { INVERTED, //!< Zero is to the right or bottom
280 NATURAL //!< Zero is to the left or top
281 };
282
283 /** Enum for drawing Mode */
284 enum class drawModeType { SET, //!< Simply set the pixel value to the new value
285 XOR, //!< See: tfrmXor()
286 ADDCLAMP, //!< See: tfrmAddClamp()
287 AND, //!< See: tfrmAnd()
288 OR, //!< See: tfrmOr()
289 DIFFCLAMP, //!< See: tfrmDiffClamp()
290 MULTCLAMP //!< See: tfrmMultClamp()
291 };
292
293 /** Enum for drawing Mode */
294 enum class interpolationType { BILINEAR, //!< bilinear
295 TRUNCATE, //!< Coordinates are truncated (fractional bits chopped off)
296 NEAREST, //!< Coordinates are rounded
297 AVERAGE4, //!< Average of four sourounding pixels
298 AVERAGE9 //!< Average of 9 sourounding pixels
299 };
300
301 //@}
302
303 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
304 /** @name Logical Maximum for intCrdT values */
305 //@{
306 const static intCrdT intCrdMax = (1ul << ((sizeof(intCrdT)*CHAR_BIT-1)/2)) - 3; //!< maximum for numPixX, numPixY, & numPix.
307 //@}
308
309 private:
310
311 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
312 /** @name Private Enumerations */
313 //@{
314 /** Endianness Identifiers. */
315 enum class endianType {
316 BIG, //!< PowerPC
317 LITTLE, //!< Intel
318 AUTO //!< Whatever the platform uses
319 };
320 //@}
321
322 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
323 /** @name intCrd Guard Valus */
324 //@{
325 const static intCrdT intCrdGrdMax = intCrdMax+1; //!< Large sentinel value (always off canvas)
326 const static intCrdT intCrdGrdMin = -1; //!< Small sentinel value (always off canvas)
327 //@}
328
329 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
330 /** @name Canvas integer coordinates */
331 //@{
332 intCrdT numPixX; //!< Number of x pixels
333 intCrdT numPixY; //!< Number of y pixels
334 intCrdT numPix; //!< Number of pixels
335 //@}
336
337 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
338 /** @name Canvas real coordinates */
339 //@{
340 fltCrdT minRealX; //!< x coord of min (real coord)
341 fltCrdT maxRealX; //!< x coord of max (real coord)
342 fltCrdT minRealY; //!< y coord of min (real coord)
343 fltCrdT maxRealY; //!< y coord of max (real coord)
344 //@}
345
346 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
347 /** @name Canvas real/integer coordinates conversion */
348 //@{
349 fltCrdT pixWidX; //!< Width of a pixel (real coord)
350 fltCrdT pixWidY; //!< Height of a pixel (real coord)
351
352 fltCrdT canvasWidX; //!< Width of the canvas (real coord)
353 fltCrdT canvasWidY; //!< height of the canvas (real coord)
354 //@}
355
356 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
357 /** @name Axis orientation */
358 //@{
359 realAxisOrientation realAxOrientationX; //!< Orientation of x axis
360 realAxisOrientation realAxOrientationY; //!< Orientation of y axis
361 intAxisOrientation intAxOrientationX; //!< Flip horizontally
363 //@}
364
365 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
366 /** @name Canvas pixel store pointers */
367 //@{
368 colorT *pixels; //!< Array to hold the color values.
369 colorT *pixelsE; //!< Point one beyond end of pixels array.
370 //@}
371
372 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
373 /** @name Drawing defaults */
374 //@{
375 colorT dfltColor; //!< Default color.
376 drawModeType drawMode; //!< Drawing mode.
377 intCrdT dfltX; //!< x coordinate used by default.
378 intCrdT dfltY; //!< y coordinate used by default.
379 //@}
380
381 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
382 /** @name Filled Triangle Utility Functions */
383 //@{
384 //--------------------------------------------------------------------------------------------------------------------------------------------------------
385 /** Utliity function behind the drawFillTriangle() functions.
386 @bug Not thread safe
387 @param x1 The x coordinate of the first point
388 @param y1 The y coordinate of the first point
389 @param x2 The x coordinate of the second point
390 @param y2 The y coordinate of the second point
391 @param x3 The x coordinate of the third point
392 @param y3 The y coordinate of the third point
393 @param c1 The color of the first point (x1, y1)
394 @param c2 The color of the second point (x2, y2)
395 @param c3 The color of the third point (x3, y3)
396 @param solid Use only c1 if true, otherwise use barycentric interpolation */
397 void drawFillTriangleUtl(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorT c1, colorT c2, colorT c3, bool solid);
398 //@}
399
400 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
401 /** @name File Writing Utility Methods */
402 //@{
403 //--------------------------------------------------------------------------------------------------------------------------------------------------------
404 /** Write an unsigned integer to a stream with given length and endianness.
405 @param oStream The ostream object to which to write
406 @param endianness The endianness to use for the integer.
407 @param numBytes The number of bytes of the data parameter to use (logically the least significant bits)
408 @param data The integer to write */
409 void writeUIntToStream(std::ostream& oStream, endianType endianness, int numBytes, uint64_t data);
410 //--------------------------------------------------------------------------------------------------------------------------------------------------------
411 /** Determine the platform's endianness. */
412 endianType platformEndianness();
413 //@}
414
415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
416 /** @name Coordinate System Manipulation (i) */
417 //@{
418 //--------------------------------------------------------------------------------------------------------------------------------------------------------
419 /** Several internal parameters are maintained within this class that make conversion between real coordinates and integer coordinate very fast. This
420 function will update the internal parameters if the real coordinate sizes or the integer coordinate sizes have changed. This function is intended for
421 internal use. An example of when to use this function is right after the integer coordinate axes have changed via a call to newIntCoordsNC(). */
422 void updRealCoords();
423 //--------------------------------------------------------------------------------------------------------------------------------------------------------
424 /** Change the logical coordinate sizes.
425 It is important that the specified coordinate sizes describe an image with FEWER pixels than the previous sizes. This function will NOT allocate a
426 new pixel array, so the previous array contents will be interpreted as valid data -- just at different coordinates. This function causes no memory
427 leaks. This function will NOT update the internal parameters related to real coordinate systems and so updRealCoords() should be called after this
428 function in most cases. This function is intended for internal use and provides no safety checks.
429 @param numPixX_p The width of the new canvas
430 @param numPixY_p The height of the new canvas */
431 void newIntCoordsNC(intCrdT numPixX_p, intCrdT numPixY_p);
432 //@}
433
434 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
435 /** @name Plane Manipulation Methods */
436 //@{
437 //--------------------------------------------------------------------------------------------------------------------------------------------------------
438 /** Destroy the current pixel memory and reallocate a new pixel space of the given size.
439 This will not clear the canvas. IT will not reallocate the canvas unless the new size is different from the current size. It will not allocate a
440 new canvas if either argument is zero or less. Updates coordinates.
441 @param numPixX_p The width of the new canvas
442 @param numPixY_p The height of the new canvas */
443 void reallocCanvas(intCrdT numPixX_p, intCrdT numPixY_p);
444 //--------------------------------------------------------------------------------------------------------------------------------------------------------
445 /** Free the pixel memory (i) */
446 void freeCanvas();
447 //--------------------------------------------------------------------------------------------------------------------------------------------------------
448 /** Points the pixels pointer at a new pixel store, and updates coordinates. Pixels pointer not changed if new_pixels is NULL */
449 void rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY);
450 //@}
451
452 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
453 /** @name Various helper functions */
454 //@{
455 //--------------------------------------------------------------------------------------------------------------------------------------------------------
456 /** Used to find the left and right edges of a triangle. */
457 void triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin);
458 //@}
459
460 public:
461
462 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
463 /** @name Raster Data Import And Export. */
464 //@{
465 //--------------------------------------------------------------------------------------------------------------------------------------------------------
466 /** Extract raster data from the image, and pack it into a typical form used by imaging applications.
467
468 Each pixel is packed into a 1, 2, 3, or 4 byte memory block with the location of each channel given by redChan, blueChan, greenChan, and alphaChan.
469 If one of these values is -1, then that channel is not extracted. For example, all of them set to -1 except redChan (set to 0), an 8-bit gray scale
470 image would be extracted. One might extract 24-bit RGB with redChan=0, greenChan=1, and blueChan=2. Add alphaChan=3, and extract 24-bit RGB with
471 alpha -- sometimes called 24-bit RGBA or 32-bit RGBA. Many systems expect the alpha bit to be first, so one might use alphaChan=0, redChan=1,
472 greenChan=2, and blueChan=3 to get ARGB. As a fine example, TARGA images use BGR -- blueChan=0, greenChan=1, and redChan=2. In summary:
473 <pre>
474 Examples of how to pack various common raster data formats
475 ..........RGB RGBA ARGB BGR ABGR Grey
476 redChan 0 0 1 2 3 0
477 greenChan 1 1 2 1 2 -1
478 blueChan 2 2 3 0 1 -1
479 alphaChan -1 3 0 -1 0 -1
480 </pre>
481 @param rasterData Unsigned char pointer to image data.
482 If NULL,then data will be allocated for image.
483 @param x1 First x coordinate first corner of sub-image to extract
484 @param x2 First x coordinate second corner of sub-image to extract
485 @param y1 First y coordinate first corner of sub-image to extract
486 @param y2 First y coordinate second corner of sub-image to extract
487 @param redChan Channel index to use for red
488 @param blueChan Channel index to use for blue
489 @param greenChan Channel index to use for green
490 @param alphaChan Channel index to use for alpha*/
491 int exportRasterData(void* &rasterData, intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, int redChan, int greenChan, int blueChan, int alphaChan);
492 //@}
493
494 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
495 /** @name Constructors & Assignment Operators */
496 //@{
497 //--------------------------------------------------------------------------------------------------------------------------------------------------------
498 /** No arg constructor. Sets numPixX and numPixY to -1, and pixels to NULL. */
499 ramCanvasTpl();
500 //--------------------------------------------------------------------------------------------------------------------------------------------------------
501 /** Copy constructor */
502 ramCanvasTpl(const ramCanvasTpl &theCanvas);
503 //--------------------------------------------------------------------------------------------------------------------------------------------------------
504 /** Most commonly used constructor.
505 The real coordinates have default values with -1 as the min values and 1 used as the max values.
506 @param numPixX_p Number of pixels in the X direction
507 @param numPixY_p Number of pixels in the Y direction
508 @param minRealX_p Minimum real x coordinate value
509 @param maxRealX_p Maximum real x coordinate value
510 @param minRealY_p Minimum real y coordinate value
511 @param maxRealY_p Maximum real y coordinate value */
512 ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p=-1, fltCrdT maxRealX_p=1, fltCrdT minRealY_p=-1, fltCrdT maxRealY_p=1);
513 //--------------------------------------------------------------------------------------------------------------------------------------------------------
514 /** Move constructor */
515 ramCanvasTpl(ramCanvasTpl&& theCanvas);
516 //--------------------------------------------------------------------------------------------------------------------------------------------------------
517 /** Move assignment operator */
518 ramCanvasTpl& operator=(ramCanvasTpl&& theCanvas);
519 //@}
520
521 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
522 /** @name Destructor */
523 //@{
524 /** Destructor deallocates memory for the canvas. */
526 //@}
527
528
529 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
530 /** @name Canvas Compositing
531
532 @warning These functions are experimental! Functionality and API are likely to change in the future.
533
534 */
535 //@{
536 //--------------------------------------------------------------------------------------------------------------------------------------------------------
537 /** Adjoin the canvas to the side of the current canvas.
538
539 @warning This function is experimental! Functionality and API are likely to change in the future.
540
541 @param theCanvas The canvas to adjoin. */
542 void adjoinCanvasRight(const ramCanvasTpl &theCanvas) {
543 intCrdT origNumPixX = getNumPixX();
544 expandCanvas(origNumPixX + theCanvas.getNumPixX(), std::max(getNumPixY(), theCanvas.getNumPixY()));
545 insertCanvas(theCanvas, origNumPixX);
546 }
547 //--------------------------------------------------------------------------------------------------------------------------------------------------------
548 /** Adjoin the canvas to the side of the current canvas.
549
550 @warning This function is experimental! Functionality and API are likely to change in the future.
551
552 @param theCanvas The canvas to adjoin. */
553 void adjoinCanvasLeft(const ramCanvasTpl &theCanvas) {
554 intCrdT origNumPixX = getNumPixX();
555 expandCanvas(origNumPixX + theCanvas.getNumPixX(), std::max(getNumPixY(), theCanvas.getNumPixY()), origNumPixX);
556 insertCanvas(theCanvas);
557 }
558 //--------------------------------------------------------------------------------------------------------------------------------------------------------
559 /** Adjoin the canvas to the side of the current canvas.
560
561 @warning This function is experimental! Functionality and API are likely to change in the future.
562
563 @param theCanvas The canvas to adjoin. */
564 void adjoinCanvasBottom(const ramCanvasTpl &theCanvas) {
565 intCrdT origNumPixY = getNumPixY();
566 expandCanvas(std::max(getNumPixX(), theCanvas.getNumPixX()), origNumPixY + theCanvas.getNumPixY(), 0, origNumPixY);
567 insertCanvas(theCanvas, 0, 0);
568 }
569 //--------------------------------------------------------------------------------------------------------------------------------------------------------
570 /** Adjoin the canvas to the side of the current canvas.
571
572 @warning This function is experimental! Functionality and API are likely to change in the future.
573
574 @param theCanvas The canvas to adjoin. */
575 void adjoinCanvasTop(const ramCanvasTpl &theCanvas) {
576 intCrdT origNumPixY = getNumPixY();
577 expandCanvas(std::max(getNumPixX(), theCanvas.getNumPixX()), origNumPixY + theCanvas.getNumPixY());
578 insertCanvas(theCanvas, 0, origNumPixY);
579 }
580 //--------------------------------------------------------------------------------------------------------------------------------------------------------
581 /** Draw the given canvas at the indicated point.
582
583 @warning This function is experimental! Functionality and API are likely to change in the future.
584
585 @param theCanvas The canvas to draw on the current canvas.
586 @param x1 X coordinate at which to place the canvas.
587 @param y1 Y coordinate at which to place the canvas. */
588 void insertCanvas(const ramCanvasTpl &theCanvas, intCrdT x1 = 0, intCrdT y1 = 0) {
589 for(intCrdT y=0; y<theCanvas.getNumPixY(); y++)
590 for(intCrdT x=0; x<theCanvas.getNumPixX(); x++)
591 drawPoint(x1+x, y1+y, theCanvas.getPxColorRefNC(x, y));
592 }
593 //@}
594
595 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
596 /** @name Canvas resize and crop */
597 //@{
598 //--------------------------------------------------------------------------------------------------------------------------------------------------------
599 /** Resize the canvas to the given size.
600 Contents of new canvas may be random data. Not guarnteed to reallocate the canvas.
601 @param new_numPixX_p The width of the new canvas
602 @param new_numPixY_p The height of the new canvas */
603 void resizeCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p);
604 //--------------------------------------------------------------------------------------------------------------------------------------------------------
605 /** Expand the current canvas.
606 The current image will appear within the new canvas at the specified location. All pixels not set by the previous image
607 will be set to the given color.
608 @param new_numPixX_p The width of the new canvas
609 @param new_numPixY_p The height of the new canvas
610 @param x1 Coord at which the left of the old image will appear in the new image
611 @param y1 Coord at which the top of the old image will appear in the new image
612 @param color Color to use for the background of the new image. */
613 void expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1 = 0, intCrdT y1 = 0, colorArgType color = colorT(colorT::minChanVal));
614 //--------------------------------------------------------------------------------------------------------------------------------------------------------
615 /** This function will crop the canvas to the given rectangular region.
616 @param x1 Left, or right, edge of region to keep.
617 @param x2 Right, or left, edge of region to keep.
618 @param y1 Left, or right, edge of region to keep.
619 @param y2 Right, or left, edge of region to keep. */
620 void cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2);
621 //@}
622
623 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
624 /** @name Coordinate System Manipulation */
625 //@{
626 /** Change the real coordinate system associated with a canvas.
627 It updates all internal parameters are required.
628 @param minRealX_p Minimum real x coordinate value
629 @param maxRealX_p Maximum real x coordinate value
630 @param minRealY_p Minimum real y coordinate value
631 @param maxRealY_p Maximum real y coordinate value */
632 void newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p);
633 //@}
634
635 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
636 /** @name Canvas comparison */
637 //@{
638 //--------------------------------------------------------------------------------------------------------------------------------------------------------
639 /** Return true if given canvas and current canvas are the same size. */
640 inline bool isSameSize(ramCanvasTpl const & inRC) const {
641 if ((numPixY == inRC.getNumPixY()) && (numPixX == inRC.getNumPixX()))
642 return true;
643 else
644 return false;
645 }
646 //--------------------------------------------------------------------------------------------------------------------------------------------------------
647 /** Return true if given canvas and current canvas are *NOT* the same size. */
648 inline bool isNotSameSize(ramCanvasTpl const & inRC) const {
649 if ((numPixY == inRC.getNumPixY()) && (numPixX == inRC.getNumPixX()))
650 return false;
651 else
652 return true;
653 }
654 //--------------------------------------------------------------------------------------------------------------------------------------------------------
655 /** Return true if corresponding pixels in each canvas are "close" as defined by colorTpl::isClose(). */
656 inline bool isClose(ramCanvasTpl const & inRC, colorChanType epsilon) const {
657 if (isNotSameSize(inRC))
658 return false;
659 for(intCrdT y=0; y<numPixY; y++)
660 for(intCrdT x=0; x<numPixX; x++)
661 if ( !(getPxColorRefNC(x, y).isClose(inRC.getPxColorRefNC(x, y), epsilon)))
662 return false;
663 return true;
664 }
665 //--------------------------------------------------------------------------------------------------------------------------------------------------------
666 /** Return true if corresponding pixels in each canvas are "equal" as defined by colorTpl::isEqual(). */
667 inline bool isEqual(ramCanvasTpl const & inRC) const {
668 if (isNotSameSize(inRC))
669 return false;
670 for(intCrdT y=0; y<numPixY; y++)
671 for(intCrdT x=0; x<numPixX; x++)
672 if ( !(getPxColorRefNC(x, y).isEqual(inRC.getPxColorRefNC(x, y))))
673 return false;
674 return true;
675 }
676 //@}
677
678 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
679 /** @name Canvas Rotation and Reflection. */
680 //@{
681 //--------------------------------------------------------------------------------------------------------------------------------------------------------
682 /** Loss-less 90 degree clockwise rotation of the canvas about the center.
683 The top row of pixels will be on the right side after the rotation. The canvas will be resized as required. The transformation is not done
684 "in place", so enough memory is required to duplicate the canvas. */
685 void rotate90CW();
686 //--------------------------------------------------------------------------------------------------------------------------------------------------------
687 /** Loss-less 90 degree counter clockwise rotation of the canvas about the center.
688 The top row of pixels will be on the left side after the rotation. The canvas will be resized as required. The transformation is not done "in
689 place", so enough memory is required to duplicate the canvas. */
690 void rotate90CCW();
691 //--------------------------------------------------------------------------------------------------------------------------------------------------------
692 /** Loss-less 180 degree rotation of the canvas about the center.
693 The top row of pixels will be on the bottom side after the rotation. The transformation is not done "in place", so enough memory is required to
694 duplicate the canvas. */
695 void rotate180();
696 //--------------------------------------------------------------------------------------------------------------------------------------------------------
697 /** Loss-less, horizontal flip of the canvas about the center.
698 The top row of pixels will be on the bottom side after the flip. The transformation is done "in place" so no extra RAM is required. */
699 void flipHorz();
700 //--------------------------------------------------------------------------------------------------------------------------------------------------------
701 /** Loss-less, vertical flip of the canvas about the center.
702 The left row of pixels will be on the right side after the flip. The transformation is done "in place" so no extra RAM is required. */
703 void flipVert();
704 //--------------------------------------------------------------------------------------------------------------------------------------------------------
705 /** Loss-less, vertical flip of the canvas about the center.
706 The top row of pixels will be on the left side after the flip, and pixel (x,y) will be in position (y,x). The canvas will be resized as required.
707 The transformation is not done "in place", so enough memory is required to duplicate the canvas. */
708 void flipTranspose();
709 //@}
710
711 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
712 /** @name Canvas Scaling. */
713 //@{
714 //--------------------------------------------------------------------------------------------------------------------------------------------------------
715 /** Scale up the image using proximal interpolation.
716 For each source pixel we create an xfactor*xfactor box filled with the color of the original pixel. The resulting images are block, but the
717 histograms stay accurate. The algorithm is very fast as it is very simple.
718 @param xfactor The factor to scale up to -- must be a positive integer. */
719 void scaleUpProximal(int xfactor);
720 //--------------------------------------------------------------------------------------------------------------------------------------------------------
721 /** Scale down using only the upper left pixel from each block.
722 This will tend to highlight horizontal and vertical detail and generally sharpen up the image. Much data is lost with this sort of scaling
723 operation.
724 @param xfactor The factor to scale up to -- must be a positive integer. */
725 void scaleDown1pt(int xfactor);
726 //--------------------------------------------------------------------------------------------------------------------------------------------------------
727 /** Scale down using only the pixel with maximum luminosity in each block.
728 Much like scaleDown1pt(), this will sharpen up a scaled image, but it will also tend to brighten up the image as well.
729 @param xfactor The factor to scale up to -- must be a positive integer. */
730 void scaleDownMax(int xfactor);
731 //--------------------------------------------------------------------------------------------------------------------------------------------------------
732 /** Scale down using the mean pixel value from each block.
733 This creates each pixel value by averaging all of the pixels that contribute -- i.e. a mean on the xfactor*xfactor pixel corresponding to each new
734 pixel. This algorithm tends to "fuzz-up" the result -- frequently used for super-sampling.
735 @param xfactor The factor to scale down to -- must be a positive integer. */
736 void scaleDownMean(int xfactor);
737 //@}
738
739 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
740 /** @name Geometric transformations (Reverse Mapping)
741
742 @warning These functions are experimental! Functionality and API are likely to change in the future.
743 */
744 //@{
745 //--------------------------------------------------------------------------------------------------------------------------------------------------------
746 /** Geometric Transform via Radial Polynomial implemented with Reverse Mapping.
747
748 @warning This function is experimental! Functionality and API are likely to change in the future.
749
750 @param RPoly RPoly is a vector listing the coefficients of a univariate polynomial in lexicographical order --
751 i.e. RPoly[0] is the coefficients on the highest power term.
752 @param rScale Scale to apply before the transformation to the *radius*.
753 @param Xo X coordinate for origin translation -- applied before RPoly and reversed after RPoly & scale.
754 @param Yo Y coordinate for origin translation -- applied before RPoly and reversed after RPoly & scale.
755 @param oScale Scale to apply after RPoly and before reverse translation.
756 @param errorColor The color to use for pixels with no valid mapping.
757 @param interpMethod Eventually this will be the interpolation method used. */
758 ramCanvasTpl geomTfrmRevRPoly(std::vector<double> const& RPoly,
759 double rScale,
760 double Xo,
761 double Yo,
762 double oScale,
763 colorArgType errorColor = colorCornerEnum::GREEN,
764 interpolationType interpMethod = interpolationType::BILINEAR);
765 //--------------------------------------------------------------------------------------------------------------------------------------------------------
766 /** Geometric Transform via bivariate polynomial implemented with Reverse Mapping.
767
768 @warning This function is experimental! Functionality and API are likely to change in the future.
769
770 @param BiPolyX Coefficients for a bivariate polynomial in lexicographical order -- used to map x coordinates.
771 @param BiPolyY Coefficients for a bivariate polynomial in lexicographical order -- used to map y coordinates.
772 @param Xo X coordinate for origin translation -- applied before BiPoly*and reversed after BiPoly*& scale.
773 @param Yo Y coordinate for origin translation -- applied before BiPoly*and reversed after BiPoly*& scale.
774 @param oScale Scale to apply after BiPoly*and before reverse translation.
775 @param errorColor The color to use for pixels with no valid mapping.
776 @param interpMethod Eventually this will be the interpolation method used. */
777 ramCanvasTpl geomTfrmRevBiPoly(std::vector<double> const& BiPolyX,
778 std::vector<double> const& BiPolyY,
779 double Xo,
780 double Yo,
781 double oScale,
782 colorArgType errorColor = colorCornerEnum::GREEN,
783 interpolationType interpMethod = interpolationType::BILINEAR);
784 //--------------------------------------------------------------------------------------------------------------------------------------------------------
785 /** Homogenious Affine Geometric Transform implemented with Reverse Mapping.
786
787 @warning This function is experimental! Functionality and API are likely to change in the future.
788
789 @verbatim
790 [1 0 T_x] [S_x 0 0] [cA sA 0] [x_in] [x_out]
791 [0 1 T_y] [0 S_y 0] [-SA cA 0] T * [y_in] => [y_out]
792 [0 0 1 ] [0 0 1] [0 0 1] [1 ] [1 ]
793 @endverbatim
794 @param HAMatrix Homogeneous affine transform matrix -- 9 elements interpreted as a row major order 3x3 matrix.
795 @param Xo X coordinate for origin translation -- applied before HAMatrixand reversed after HAMatrix& scale.
796 @param Yo Y coordinate for origin translation -- applied before HAMatrixand reversed after HAMatrix& scale.
797 @param oScale Scale to apply after HAMatrixand before reverse translation.
798 @param errorColor The color to use for pixels with no valid mapping.
799 @param interpMethod Eventually this will be the interpolation method used. */
800 ramCanvasTpl geomTfrmRevAff(std::vector<double> const& HAMatrix,
801 double Xo,
802 double Yo,
803 double oScale,
804 colorArgType errorColor = colorCornerEnum::GREEN,
805 interpolationType interpMethod = interpolationType::BILINEAR);
806 //--------------------------------------------------------------------------------------------------------------------------------------------------------
807 /** Geometric Transform via provided mapping function implemented with Reverse Mapping.
808
809 @warning This function is experimental! Functionality and API are likely to change in the future.
810
811 @param f The coordinate transformation function
812 @param Xo X coordinate for origin translation -- applied before f and reversed after f & scale.
813 @param Yo Y coordinate for origin translation -- applied before f and reversed after f & scale.
814 @param oScale Scale to apply after f and before reverse translation.
815 @param errorColor The color to use for pixels with no valid mapping.
816 @param interpMethod Eventually this will be the interpolation method used. */
817 ramCanvasTpl geomTfrmRevArb(mjr::point2d<double> (*f)(double, double),
818 double Xo,
819 double Yo,
820 double oScale,
821 colorArgType errorColor = colorCornerEnum::GREEN,
822 interpolationType interpMethod = interpolationType::BILINEAR);
823 //@}
824
825 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
826 /** @name Apply Convolution */
827 //@{
828 //--------------------------------------------------------------------------------------------------------------------------------------------------------
829 /** Apply a convolution filter.
830 The implementation for this method is quite naive and super slow! Frankly, this kind of functionality is beyond the scope of this library; however,
831 sometimes you just need a convolution filter and you don't want to go to the extra effort of using yet another external library. Pixels outside the
832 canvas are considered black.
833 @param kernel The convolution kernel. Must be of length kWide*kTall.
834 @param kWide The width of the kernel. Must be odd.
835 @param kTall The height of the kernel. Must be odd.
836 @param divisor Used to normalize dot product at each step. i.e. one might say the kernel for the convolution is really kernel/divisor. */
837 void convolution(double *kernel, int kWide, int kTall, double divisor);
838 void convolution(double *kernel, int kSize, double divisor);
839 void convolution(double *kernel, int kSize);
840 //@}
841
842 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
843 /** @name Compute Convolution Kernels */
844 //@{
845 //--------------------------------------------------------------------------------------------------------------------------------------------------------
846 /** Compute a Gaussian convolution kernel (use with divisor==1.0).
847 @param kernel Pointer to space for the convolution kernel. Must have at least space for kSize*kSize doubles
848 @param kSize The width and height of the kernel. Must be odd.
849 @param sd The standard deviation. */
850 void computeConvolutionMatrixGausian(double *kernel, int kSize, double sd);
851 //--------------------------------------------------------------------------------------------------------------------------------------------------------
852 /** Compute a box blur convolution kernel (use with divisor==1.0).
853 @param kernel Pointer to space for the convolution kernel. Must have at least space for kSize*kSize doubles
854 @param kSize The width and height of the kernel. Must be odd. */
855 void computeConvolutionMatrixBox(double *kernel, int kSize);
856 //@}
857
858 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
859 /** @name Iterators */
860 //@{
861 colorT *begin() { return pixels; }
862 colorT *end() { return pixelsE; }
863 //@}
864
865 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
866 /** @name Functional Homogeneous Pixel Transformations (point operators) */
867 //@{
868 //--------------------------------------------------------------------------------------------------------------------------------------------------------
869 /** Apply a homogeneous pixel transformation.
870 Homogeneous pixel transformations don't vary based upon the coordinates of the pixel in question, but depend only upon the value of the pixel.
871 Thus, a homogeneous pixel transformation can be considered as a pixel function applied to each pixel in an image. Many standard pixel functions are
872 defined within the colorT object. The ramCanvasTpl object must then only apply the methods available within each colorT class to support most of
873 the standard homogeneous pixel transformations. Additionally, new functions are automatically available to the ramCanvasTpl (both in the colorT
874 class and new functions from other sources). */
875 void applyHomoPixTfrm(colorT& (colorT::*HPT)());
876 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double), double);
877 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double, double);
878 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double, double, double);
879 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double), double, double, double, double);
880 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double), double, double, double, double, double);
881 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double), double, double, double, double, double, double);
882 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int), int);
883 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int, int);
884 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int, int, int);
885 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int, int, int, int);
886 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT), colorT);
887 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT, colorT);
888 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT, colorT, colorT);
889 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT, colorT, colorT, colorT);
890 //@}
891
892 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
893 /** @name Predefined Homogeneous Pixel Transformations (point operators) */
894 //@{
895 //--------------------------------------------------------------------------------------------------------------------------------------------------------
896 /** Computes a linear grey level scale homogeneous pixel transformation.
897 f(c)=(c-cmin)*maxChanVal/(cmax-cmin) where cmin is the lowest integer value assumed by any pixel color component and cmax is the largest integer value
898 assumed by any pixel color component. This function is sometimes called "auto contrast adjust" or "linear auto contrast adjust". */
899 void autoHistStrech();
900 //--------------------------------------------------------------------------------------------------------------------------------------------------------
901 /** Computes a, possibly different, linear grey level scale homogeneous pixel transformation on each channel of the image.
902 Channel n is transformed such that f_n(c)=(c-cmin_n)*maxChanVal/(cmax_n-cmin_n) where cmin_n and cmax_n are the minimum and maximum values in channel n.
903 i.e. this is the same as applying autoHistStrech independently to each channel.*/
904 void autoMaxHistStrechRGB();
905 //@}
906
907 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
908 /** @name Canvas Combination Functions */
909 //@{
910 //--------------------------------------------------------------------------------------------------------------------------------------------------------
911 /** This function takes a ramCanvasTpl and combines it with the current ramCanvasTpl using the provided binary operator.
912 @param HPT Pointer to a binary operator.
913 @param theCanvas This is the ramCanvasTpl to combine with.
914 @param trgX Final X coordinate for the left of the combined region. Default: 0
915 @param trgY Final Y coordinate for the top of the combined region. Default: 0
916 @param srcX Left edge of the region to combine with. Default: 0
917 @param srcY Top edge of the region to combine with. Default: 0
918 @param wide Width of the region to combine with. Default: -1 (indicates to edge of canvas)
919 @param tall Height of the region to combine with. Default: -1 (indicates to edge of canvas) */
920 void combineRamCanvasBinOp(colorT& (colorT::*HPT)(colorT),
921 const ramCanvasTpl &theCanvas,
922 intCrdT trgX = 0, intCrdT trgY = 0,
923 intCrdT wide = -1, intCrdT tall = -1,
924 intCrdT srcX = 0, intCrdT srcY = 0);
925 //@}
926
927 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
928 /** @name Statistical Canvas Combination Functions (useful for CCD imaging) */
929 //@{
930 //--------------------------------------------------------------------------------------------------------------------------------------------------------
931 /** Take a list of ramCanvasTpl objects and combine them with the current ramCanvasTpl using mean.
932 @param theCanvasList This is the array of ramCanvasTpl's to combine with.
933 @param N The number of canvas objects. */
934 void combineRamCanvasMean(ramCanvasTpl *theCanvasList, const int N);
935 //@}
936
937 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
938 /** @name Canvas Clearing Methods */
939 //@{
940 //--------------------------------------------------------------------------------------------------------------------------------------------------------
941 /** Clear the canvas to black. Faster than clrCanvas(). */
942 void clrCanvasToBlack();
943 //--------------------------------------------------------------------------------------------------------------------------------------------------------
944 /** Clear the canvas to black. Faster than clrCanvas(). */
945 void clrCanvasToWhite();
946 //--------------------------------------------------------------------------------------------------------------------------------------------------------
947 /** Set the given channel to the minimum value. */
948 void clrCanvasChannelToMin(int chan);
949 //--------------------------------------------------------------------------------------------------------------------------------------------------------
950 /** Set the given channel to the maximum value. */
951 void clrCanvasChannelToMax(int chan);
952 //--------------------------------------------------------------------------------------------------------------------------------------------------------
953 /** Clear the canvas. */
954 void clrCanvas();
955 //--------------------------------------------------------------------------------------------------------------------------------------------------------
956 /** @overload */
957 void clrCanvas(colorArgType color);
958 //@}
959
960 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
961 /** @name Default Point Methods */
962 //@{
963 //--------------------------------------------------------------------------------------------------------------------------------------------------------
964 /** Set the current default point to the given coordinates.
965 @param x The x coordinate of the point to move to.
966 @param y The y coordinate of the point to move to. */
967 inline void moveTo(intCrdT x, intCrdT y) { dfltX = x; dfltY = y; }
968 inline void moveTo(fltCrdT x, fltCrdT y) { moveTo(real2intX(x), real2intY(y)); }
969 inline void moveTo(pointIntType thePoint) { moveTo(thePoint.x, thePoint.y); }
970 inline void moveTo(pointFltType thePoint) { moveTo(real2intX(thePoint.x), real2intY(thePoint.y)); }
971 //@}
972
973 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
974 /** @name Default Color Methods */
975 //@{
976 //--------------------------------------------------------------------------------------------------------------------------------------------------------
977 /** Set the default color */
978 inline void setDfltColor(colorArgType color) { dfltColor = color; }
979 inline void setDfltColor(std::string cornerColor) { dfltColor.setToCorner(cornerColor); }
980 inline void setDfltColor(const char* cornerColor) { dfltColor.setToCorner(std::string(cornerColor)); }
981 inline void setDfltColor(colorChanType r, colorChanType g, colorChanType b) { dfltColor.setChansRGB(r, g, b); }
982 //@}
983
984 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
985 /** @name Point drawing functions */
986 //@{
987 //--------------------------------------------------------------------------------------------------------------------------------------------------------
988 /** Draw a point at the specified coordinates with the specified color.
989 Overloaded versions exist with various arguments.
990 @param x The x coordinate of the point
991 @param y The y coordinate of the point
992 @param color The color to draw the point */
993 inline void drawPoint(intCrdT x, intCrdT y, colorArgType color) {
994 if(isOnCanvas(x, y))
995 drawPointNC(x, y, color);
996 }
997 inline void drawPoint() { drawPoint(dfltX, dfltY, dfltColor); }
998 inline void drawPoint(colorArgType color) { drawPoint(dfltX, dfltY, color); }
999 inline void drawPoint(intCrdT x, intCrdT y) { drawPoint(x, y, dfltColor); }
1000 inline void drawPoint(fltCrdT x, fltCrdT y) { drawPoint(x, y, dfltColor); }
1001 inline void drawPoint(fltCrdT x, fltCrdT y, colorArgType color) { drawPoint(real2intX(x), real2intY(y), color); }
1002 inline void drawPoint(pointIntType thePoint, colorArgType color) { drawPoint(thePoint.x, thePoint.y, color); }
1003 inline void drawPoint(pointIntType thePoint) { drawPoint(thePoint.x, thePoint.y, dfltColor); }
1004 inline void drawPoint(pointFltType thePoint) { drawPoint(real2intX(thePoint.x), real2intY(thePoint.y), dfltColor); }
1005 inline void drawPoint(pointFltType thePoint, colorArgType color) { drawPoint(real2intX(thePoint.x), real2intY(thePoint.y), color); }
1006 //@}
1007
1008 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1009 /** @name Line Drawing Methods */
1010 //@{
1011 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1012 /** Draw a line.
1013 This function is optimized for speed, and has special code for handling lines of slope 0, 1, -1, and infinity. Line is clipped to the
1014 current canvas.
1015 @param x1 x coordinate of the first point
1016 @param y1 y coordinate of the first point
1017 @param x2 x coordinate of the second point
1018 @param y2 y coordinate of the second point
1019 @param color The color to use
1020
1021 @par Performance Note
1022 This function will perform better if (x1,y2) and (x2,y2) are in the clip region. Further x1<x2 will save several steps in
1023 the algorithm.
1024
1025 @par Algorithm Notes
1026 This function treats lines of slope 0, 1, -1, and infinity as special cases. Special clipping and drawing algorithms are used for each case. All
1027 other lines are broken up into four classes by slope: 0<m<1, 1<m<infinity, -1<m<0, and -infinity<m<-1. Separate line clipping algorithms are used
1028 for positive slope lines and for negative slope lines.
1029
1030 The algorithms used to draw lines in the last four cases are related to the classic algorithm presented by Bresenham in 1965 and the
1031 extensions to Bresenham's algorithm given by Pitteway in 1967 and Van Aken in 1984. The basic algorithm described by Bresenham, Pitteway, and Van
1032 Aken is known as the "Midpoint Algorithm". For the case 0<m<1, the algorithm used is actually the midpoint algorithm, and the remaining cases are
1033 obvious extensions to the midpoint algorithm. Each case is customized and optimized for the given slope class.
1034
1035 The clipping algorithm used for the last slope classes is similar in spirit to the Cohen-Sutherland Line-Clipping algorithm, but is optimized
1036 for each slope class. Several pre-checks are made in order to avoid the slope computations in the Cohen-Sutherland algorithm -- in fact intersections
1037 are only computed if absolutely required. Note that the only floating point computations in this function are the intersection computations, and they
1038 will be avoided completely if the given line need not be clipped.*/
1039 void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1040 inline void drawLine(pointFltType point1) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), dfltColor); }
1041 inline void drawLine(pointFltType point1, colorArgType color) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), color); }
1042 inline void drawLine(pointIntType point1) { drawLine( dfltX, dfltY, point1.x, point1.y, dfltColor); }
1043 inline void drawLine(pointIntType point1, colorArgType color) { drawLine( dfltX, dfltY, point1.x, point1.y, color); }
1044 inline void drawLine(pointFltType point1, pointFltType point2) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1045 inline void drawLine(pointFltType point1, pointFltType point2, colorArgType color) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1046 inline void drawLine(pointIntType point1, pointIntType point2) { drawLine( point1.x, point1.y, point2.x, point2.y, dfltColor); }
1047 inline void drawLine(pointIntType point1, pointIntType point2, colorArgType color) { drawLine( point1.x, point1.y, point2.x, point2.y, color); }
1048 inline void drawLine(intCrdT x, intCrdT y) { drawLine( dfltX, dfltY, x, y, dfltColor); }
1049 inline void drawLine(fltCrdT x, fltCrdT y) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), dfltColor); }
1050 inline void drawLine(intCrdT x, intCrdT y, colorArgType color) { drawLine( dfltX, dfltY, x, y, color); }
1051 inline void drawLine(fltCrdT x, fltCrdT y, colorArgType color) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), color); }
1052 inline void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
1053 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
1054 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawLine( real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1055 //@}
1056
1057 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1058 /** @name Unfilled Triangle Drawing Methods */
1059 //@{
1060 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1061 /** Draw an un-filled triangle
1062 @bug Some pixels may be drawn more than once.
1063 @param x1 The x coordinate of the first point
1064 @param y1 The y coordinate of the first point
1065 @param x2 The x coordinate of the second point
1066 @param y2 The y coordinate of the second point
1067 @param x3 The x coordinate of the third point
1068 @param y3 The y coordinate of the third point
1069 @param color The color to use for the triangle */
1070 void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1071 inline void drawTriangle(pointIntType *thePoints, colorArgType color) { drawTriangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, thePoints[2].x, thePoints[2].y, color); }
1072 inline void drawTriangle(pointFltType *thePoints) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1073 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1074 real2intX(thePoints[2].x), real2intY(thePoints[2].y), dfltColor); }
1075 inline void drawTriangle(pointFltType *thePoints, colorArgType color) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1076 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1077 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1078 inline void drawTriangle(pointIntType *thePoints) { drawTriangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, thePoints[2].x, thePoints[2].y, dfltColor); }
1079 inline void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1080 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1081 real2intX(point2.x), real2intY(point2.y),
1082 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1083 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1084 real2intX(point2.x), real2intY(point2.y),
1085 real2intX(point3.x), real2intY(point3.y), color); }
1086 inline void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3, colorArgType color) { drawTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, color); }
1087 inline void drawTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3) { drawTriangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), real2intX(x3), real2intY(y3), dfltColor); }
1088 inline void drawTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color) { drawTriangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), real2intX(x3), real2intY(y3), color); }
1089 inline void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1090 //@}
1091
1092 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1093 /** @name Filled Triangle Drawing Methods */
1094 //@{
1095 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1096 /** Draw a triangle filled with a solid color using a nicely optimized, horizontal scan conversion algorithm.
1097 @bug Triangles not entirely on the canvas are not rendered.
1098 @bug Not thread safe.
1099 @param x1 The x coordinate of the first point
1100 @param y1 The y coordinate of the first point
1101 @param x2 The x coordinate of the second point
1102 @param y2 The y coordinate of the second point
1103 @param x3 The x coordinate of the third point
1104 @param y3 The y coordinate of the third point
1105 @param color The color to use for the triangle */
1106 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1107 inline void drawFillTriangle(pointIntType *thePoints, colorArgType color) { drawFillTriangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, thePoints[2].x, thePoints[2].y, color); }
1108 inline void drawFillTriangle(pointFltType *thePoints) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1109 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1110 real2intX(thePoints[2].x), real2intY(thePoints[2].y), dfltColor); }
1111 inline void drawFillTriangle(pointFltType *thePoints, colorArgType color) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1112 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1113 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1114 inline void drawFillTriangle(pointIntType *thePoints) { drawFillTriangle(thePoints[0].x, thePoints[0].y,
1115 thePoints[1].x, thePoints[1].y,
1116 thePoints[2].x, thePoints[2].y, dfltColor); }
1117 inline void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawFillTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1118 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1119 real2intX(point2.x), real2intY(point2.y),
1120 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1121 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1122 real2intX(point2.x), real2intY(point2.y),
1123 real2intX(point3.x), real2intY(point3.y), color); }
1124 inline void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3, colorArgType color) { drawFillTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, color); }
1125 inline void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3) { drawFillTriangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), real2intX(x3), real2intY(y3), dfltColor); }
1126 inline void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color) { drawFillTriangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), real2intX(x3), real2intY(y3), color); }
1127 inline void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawFillTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1128 //@}
1129
1130 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1131 /** @name Shaded Triangle Drawing Methods */
1132 //@{
1133 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1134 /** Draw a filled triangle using barycentric color interpolation.
1135 @bug Triangles not entirely on the canvas are not rendered.
1136 @bug Degenerate trainagles are not rendered
1137 @bug Painfully slow
1138 @param x1 The x coordinate of the first point
1139 @param y1 The y coordinate of the first point
1140 @param x2 The x coordinate of the second point
1141 @param y2 The y coordinate of the second point
1142 @param x3 The x coordinate of the third point
1143 @param y3 The y coordinate of the third point
1144 @param color1 The color of the first point (x1, y1)
1145 @param color2 The color of the second point (x2, y2)
1146 @param color3 The color of the third point (x3, y3) */
1147 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color1, colorArgType color2, colorArgType color3);
1148 //@}
1149
1150 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1151 /** @name Unfilled Rectangle Drawing Functions */
1152 //@{
1153 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1154 /** Draw an unfilled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1155 Best performance will be achieved if (x1, y1) is the upper left corner, and (x2,y2) is the lower left corner and both (x1,y1) and (x2,y2) are within
1156 the bounds of the canvas using the specified color.
1157 @param x1 The x coordinate of first corner
1158 @param y1 The y coordinate of first corner
1159 @param x2 The x coordinate of second corner
1160 @param y2 The y coordinate of second corner
1161 @param color The color to use */
1162 void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1163 inline void drawRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1164 inline void drawRectangle(pointIntType point1, pointIntType point2) { drawRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1165 inline void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1166 inline void drawRectangle(pointFltType point1, pointFltType point2) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1167 inline void drawRectangle(pointIntType *thePoints, colorArgType color) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1168 inline void drawRectangle(pointFltType *thePoints) { drawRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1169 inline void drawRectangle(pointFltType *thePoints, colorArgType color) { drawRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), color); }
1170 inline void drawRectangle(pointIntType *thePoints) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1171 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1172 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1173 inline void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawRectangle(x1, y1, x2, y2, dfltColor); }
1174 //@}
1175
1176 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1177 /** @name Filled Rectangle Drawing Methods */
1178 //@{
1179 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1180 /** Draw a filled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1181 Best performance will be achieved if (x1, y1) is the upper left corner, and (x2,y2) is the lower left corner and both (x1,y1) and (x2,y2) are within
1182 the bounds of the canvas using the specified color.
1183 @param x1 The x coordinate of first corner
1184 @param y1 The y coordinate of first corner
1185 @param x2 The x coordinate of second corner
1186 @param y2 The y coordinate of second corner
1187 @param color The color to use */
1188 void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1189 inline void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1190 inline void drawFillRectangle(pointIntType point1, pointIntType point2) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1191 inline void drawFillRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1192 inline void drawFillRectangle(pointFltType point1, pointFltType point2) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1193 inline void drawFillRectangle(pointIntType *thePoints, colorArgType color) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1194 inline void drawFillRectangle(pointFltType *thePoints) { drawFillRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1195 inline void drawFillRectangle(pointFltType *thePoints, colorArgType color) { drawFillRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), color); }
1196 inline void drawFillRectangle(pointIntType *thePoints) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1197 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1198 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1199 inline void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawFillRectangle(x1, y1, x2, y2, dfltColor); }
1200 //@}
1201
1202 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1203 /** @name Unfilled Circle Drawing Methods */
1204 //@{
1205 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1206 /** Draw an un-filled circle.
1207 The algorithm used is based upon the one presented in "A Linear Algorithm for Incremental Digital Display of Circular Arcs" published in the
1208 Communications of the AMC in Feb 1977 and written by J.E. Bresenham. Bresenham's algorithm has been significantly improved by using only integer
1209 arithmetic and adding second order differences to the computation -- much the way the line drawing algorithm works in this package. The algorithm
1210 is essentially a scan line conversion algorithm, so the circle is always approximately one pixel thick. One subtle point: The real X and Y axes in
1211 this package can have different scaling. This means that one must pick a direction in which the radius will be measured in real coordinate deltas.
1212 In this function, that direction is along the X axis -- i.e. the radius of the drawn circle will be measured horizontally. This function is well
1213 optimized.
1214 @bug Draws everyting even if it's off the canvas.
1215 @param centerX The x coordinate of the center
1216 @param centerY The y coordinate of the center
1217 @param radiusX The radius of the circle
1218 @param color The color to draw the circle with */
1219 void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1220 inline void drawCircle(intCrdT radiusX) { drawCircle(dfltX, dfltY, radiusX, dfltColor); }
1221 inline void drawCircle(fltCrdT radiusX) { drawCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1222 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1223 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1224 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX) { drawCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1225 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1226 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1227 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1228 inline void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawCircle(centerX, centerY, radiusX, dfltColor); }
1229 //@}
1230
1231 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1232 /** @name Filled Circle Drawing Methods */
1233 //@{
1234 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1235 /** Draw an un-filled circle.
1236 The algorithm used to compute circle edge points is the same as that used in drawCircle; however, the algorithm used to fill the circle is of my own
1237 design. I doubt that it is new, but I have never come across it in my readings -- not that I have looked too hard. The algorithm has the advantage
1238 that most of the interior points are only drawn one time. One subtle point: The real X and Y axes in this package can have different scaling. This
1239 means that one must pick a direction in which the radius will be measured in real coordinate deltas. In this function, that direction is along the
1240 X axis -- i.e. the radius of the drawn circle will be measured horizontally. This function is well optimized.
1241 @bug Draws everyting even if it's off the canvas.
1242 @param centerX The x coordinate of the center
1243 @param centerY The y coordinate of the center
1244 @param radiusX The radius of the circle
1245 @param color The color to draw the circle with */
1246 void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1247 inline void drawFillCircle(fltCrdT radiusX) { drawFillCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1248 inline void drawFillCircle(intCrdT radiusX) { drawFillCircle(dfltX, dfltY, radiusX, dfltColor); }
1249 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1250 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1251 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1252 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1253 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1254 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1255 inline void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawFillCircle(centerX, centerY, radiusX, dfltColor); }
1256 //@}
1257
1258 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1259 /** @name Piece-Wise Linear Curve Drawing Methods */
1260 //@{
1261 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1262 /** Draw Piece-Wise Linear Curves
1263 @bug Some pixels may be drawn more than once.
1264 */
1265 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y, colorArgType color);
1266 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y);
1267 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y, colorArgType color);
1268 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y);
1269 void drawPLCurve(int numPoints, pointIntType *thePoints, colorArgType color);
1270 void drawPLCurve(int numPoints, pointIntType *thePoints);
1271 void drawPLCurve(int numPoints, pointFltType *thePoints, colorArgType color);
1272 void drawPLCurve(int numPoints, pointFltType *thePoints);
1273 //@}
1274
1275 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1276 /** @name Hershey Glyph Rendering Utility Functions */
1277 //@{
1278 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1279 /** Render a glyph from the Hershey character set.
1280 The glyph is rendered with its origin at the given coordinates. This function is intended to provide only the most basic glyph rendering. For
1281 example, glyphs are rendered with the line drawing functions, and therefore are not anti-aliased.
1282 @param glyphNum The character number of the glyph to render
1283 @param x The x coordinate at which to render the glyph
1284 @param y The x coordinate at which to render the glyph
1285 @param magX The magnification of the glyph in the x direction
1286 @param magY The magnification of the glyph in the y direction
1287 @param aColor The color with which to render the glyph */
1288 void drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor);
1289 void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor) { drawHersheyGlyph(glyphNum, real2intX(x), real2intY(y), magX, magY, aColor); }
1290 //@}
1291
1292 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1293 /** @name ASCII Character Rendering.
1294 What are font rendering functions doing in a raster graphics library? Sometimes I like to put a label on image.*/
1295 //@{
1296 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1297 /** Render a string using Hershey ASCII Fonts.
1298 While the string is rendered with fixed font spacing, the Hershey fonts are not fixed width fonts.
1299 @param aString The string
1300 @param aFont The font to set the default with
1301 @param x The x coordinate at which to render the first glyph
1302 @param y The x coordinate at which to render the first glyph
1303 @param aColor The color with which to render the glyphs
1304 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1305 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1306 void drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc);
1307 void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc) {
1308 drawString(aString, aFont, real2intX(x), real2intY(y), aColor, cex, spc);
1309 }
1310 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1311 /** Renders a filled, bounding box for the given string as rendered via drawString.
1312 @param aString A string to render
1313 @param aFont The font to set the default with
1314 @param x The x coordinate at which to render the first glyph
1315 @param y The x coordinate at which to render the first glyph
1316 @param stringColor The color with which to render the glyphs
1317 @param boxColor The color with which to render the BOX
1318 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1319 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1320 void drawStringBox(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc);
1321 void drawStringBox(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc) {
1322 drawStringBox(aString, aFont, real2intX(x), real2intY(y), stringColor, boxColor, cex, spc);
1323 }
1324 //@}
1325
1326 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1327 /** @name File Reading and Writing Methods */
1328 //@{
1329 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1330 /** Is libTIFF supported -- that is: will the readTIFFfile() method do anything?
1331 Note that readTIFFfile() is the only method that needs libTIFF. In particular, writeTIFFfile() works without libTIFF. */
1332 bool supportLibTIFF();
1333 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1334 /** If the libTIFF library was found at build time, this function will read a TIFF file into current ramCanvas object.
1335
1336 If libTIFF is not supported, then this function returns 32. You can test if this method works via the supportLibTIFF() method.
1337
1338 Notable features:
1339 - Arbitrary TIFF image file types are converted to 24-bit RGB when aRamCanvas is of type ramCanvas3c8b
1340 - Note aRamCanvas must be of type ramCanvas3c8b -- ramCanvas4c8b is not good enough.
1341 - Reasonable conversions are made in other cases.
1342 - if aRamCanvas has fewer channels than the TIFF file, then extra channels in the TIFF file are ignored
1343 - if aRamCanvas has more channels than the TIFF file, then extra channels of aRamCanvas are set to black
1344 - if aRamCanvas and the TIFF have different channel widths, then the TIFF data is scaled (TIFF data is assumed to be full scale. Max tags are ignored)
1345 - Some effort is taken to do the right thing with respect to aRamCanvas axis orientation
1346
1347 @param fileName The file name from which to read data from.
1348 @retval 0 Image file loaded successfully
1349 @retval 1 File open (TIFFOpen) failure
1350 @retval 2 File missing TIFF tag: IMAGEWIDTH
1351 @retval 3 File missing TIFF tag: IMAGELENGTH
1352 @retval 4 File missing TIFF tag: SAMPLESPERPIXEL
1353 @retval 5 File missing TIFF tag: PLANARCONFIG
1354 @retval 6 File missing TIFF tag: PHOTOMETRIC
1355 @retval 7 File missing TIFF tag: BITSPERSAMPLE
1356 @retval 8 File of zero width
1357 @retval 9 File of zero height
1358 @retval 10 Allocation failed (temp image buffer)
1359 @retval 11 Read (TIFFReadRGBAImage) failure
1360 @retval 12 Canvas Allocation failed (insufficient width)
1361 @retval 14 Canvas Allocation failed (insufficient height)
1362 @retval 15 TIFF bps not 8, 16, 32, or 64
1363 @retval 16 Allocation failed (scan line buffer)
1364 @retval 17 Read (TIFFReadScanline) failure
1365 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1366 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1367 @retval 20 File and ramCanvas channel depth differ
1368 @retval 21 File and ramCanvas channel format (int vs float) differ
1369 @retval 22 Planar configuration is invalid (not 1 or 2)
1370 @retval 32 TIFF read support not provided in this compile */
1371 int readTIFFfile(std::string fileName);
1372 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1373 /** Write a TIFF format image file. Respects integer coordinate system orientation.
1374
1375 Why TIFF? TIFF is both broadly supported and flexible enough to represent almost every ramCanvas image type perfectly.
1376
1377 Use Cases (In order of priority)
1378 - Write a bit perfect TIFF representation of ramCanvas images
1379 - Simultaneously convert any ramCanvas into 24-bit truecolor RGB and write the resulting TIFF
1380 - Do all the above while simultaneously applying a homogeneous image filter
1381
1382 Limitations
1383 - Channels must be no more than 64-bits wide
1384 - No more than 2^16-1 channels
1385 - Image width no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1386 - Image height no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1387 - Image row data size (numPixX * colorT::bitsPerChan * colorT::channelCount / 8) must be less than 2^32-1 bytes
1388 - Image data must be less than 2^32-1 bytes
1389
1390 Limitations for bit perfect (toTRU is NULL) files:
1391 - Channels must be uint8_t, uint16_t, uint32_t, uint64_t, float (32-bit), or double (64-bit)
1392
1393 @param fileName The file name to write data to
1394 @param rcConverter An rcConverter object instance
1395 @param markAlpha If an alpha channel is present, then mark it as such in the TIFF file.
1396 @return Status of I/O
1397 @retval 0 Everything seems to have worked
1398 @retval 2 Image channels are too shallow for TIFF format
1399 @retval 3 Image channels are too deep for TIFF format
1400 @retval 4 Image has too few channels for TIFF format
1401 @retval 5 Image has too many channels for TIFF format
1402 @retval 6 Image has too few columns for TIFF format
1403 @retval 7 Image has too many columns for TIFF format
1404 @retval 8 Image has too few rows for TIFF format
1405 @retval 9 Image has too few rows for TIFF format
1406 @retval 10 Image rows are too large (too much data) for TIFF format
1407 @retval 11 Image is too large (too much data) for TIFF format */
1408 template <class rcConT> int writeTIFFfile(std::string fileName, rcConT rcConverter, bool markAlpha);
1409 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1410 /** Simplified overload for writeTIFFfile() that only requires the filename. */
1411 int writeTIFFfile(std::string fileName, bool markAlpha = true);
1412 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1413 /** Write a 24-bit (8-bit per channel) RGB, TGA format graphics file. Respects integer coordinate system orientation.
1414
1415 Why TGA? TGA files are not well supported by modern software. When supported, it is normally only 8-bit RGBA. With these limitations one might ask
1416 why this function exists. I am a POV-Ray fan, and it uses a specialized TGA format for height maps. That's really it... One could use this
1417 function to dump out regular RGB images, but I suggest writeTIFFfile() for that.
1418
1419 Note TGA files are 8-bit files, and *_byte functions are used to convert channel values to 8-bit before being written.
1420
1421 @param fileName The file name name to write data to
1422 @return Status of I/O
1423 @retval 0 Everything seems to have worked
1424 @retval 1 File open failure
1425 @retval 6 Image of zero width
1426 @retval 7 Image too wide for TGA format (> 2^16-1)
1427 @retval 8 Image of zero height
1428 @retval 9 Image too tall for TGA format (> 2^16-1) */
1429 int writeTGAfile(std::string fileName);
1430 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1431 /** Read RAW file
1432
1433 @warning This function is experimental! Functionality and API are likely to change in the future.
1434
1435 @bug Floating point data is read directly from disk as-is without regard for endianness. I have no plans to fix this because I'm not sure what a
1436 good fix looks like
1437
1438 @retval 0 Image file loaded successfully
1439 @retval 1 File open failure
1440 @retval 2 NOT USED
1441 @retval 3 NOT USED
1442 @retval 4 NOT USED
1443 @retval 5 NOT USED
1444 @retval 6 NOT USED
1445 @retval 7 NOT USED
1446 @retval 8 File of zero width
1447 @retval 9 File of zero height
1448 @retval 10 NOT USED
1449 @retval 11 Read failure
1450 @retval 12 Canvas Allocation failed (insufficient width)
1451 @retval 14 Canvas Allocation failed (insufficient height)
1452 @retval 15 bps not 8, 16, 32, or 64
1453 @retval 16 NOT USED
1454 @retval 17 NOT USED
1455 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1456 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1457 @retval 20 File and ramCanvas channel depth differ
1458 @retval 21 File and ramCanvas channel format (int vs float) differ
1459 @retval 22 NOT USED
1460 @retval 23 File is signed integer or unsigned float
1461 @retval 24 File is missing MJRRAW magic number
1462 @retval 25 Image data read failure (file may have ended prematurely)
1463 @retval 26 Malformed header
1464 @retval 27 Image is too wide to be supported by ramCanvas
1465 @retval 28 Image is too tall to be supported by ramCanvas
1466 @retval 29 Error reading numbers in header
1467 @retval 32 NOT USED
1468 @retval 33 Image width missing from header
1469 @retval 34 Image height missing from header
1470 @retval 35 Image channel count missing from header
1471 @retval 36 Image channel depth missing from header */
1472 int readRAWfile(std::string fileName);
1473 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1474 /** Write a MJRRAW file. Respects integer coordinate system orientation.
1475
1476 Why? This simple file format is designed to house the more exotic images this library supports, and be easily consumed by many image processing and
1477 data visualization tools -- usually via a feature referred to as a raw importer. ImageMagick, VisIT, ParaView, and ImageJ all can read this type of
1478 data. The header is exactly 100 bytes, ASCII, and contains two newlines. The idea being that one can do a 'head -n 2 FILENAME' on the image file,
1479 and get a human readable output of basic image info that also happens to be easy to parse. The first line of the header is the text "MJRRAW". The
1480 second line of the header consists of a sequence of values& value labels and followed by enough zero characters to pad to get to the 100 byte mark.
1481 That's 100 bytes for the two lines including the two newline characters. The values consist of uppercase letters and numbers, and each label is a
1482 single lower case letter. If a value is a number, then it is expressed as a decimal number in ASCII using -- it may be zero padded. While the code
1483 in ramCanvasTpl doesn't make assumptions about the order of the header values, some of the example scripts require them to be in the following
1484 order: x, y, c, b, s, t, & i. The header is followed by the binary image.
1485
1486 Labels:
1487 - x: Number of pixels on X (horizontal axis) expressed as a zero padded, decimal integer
1488 - y: Number of pixels on Y (vertical axis) expressed as a zero padded, decimal integer
1489 - c: Number of channels expressed as a zero padded, decimal integer
1490 - b: Number of bits per channel expressed as a zero padded, decimal integer
1491 - s: Channel signdness (ignored for floating point channels)
1492 - UNS: Unsigned data. DEFAULT VALUE.
1493 - SGN: Signed data
1494 - t: Channel type
1495 - INT: Integral channels. DEFAULT VALUE.
1496 - FLT: Floating point channels
1497 - i: endianness
1498 - BIG: Big endian
1499 - LTL: Little endian
1500 - UNK: Unknown. DEFAULT VALUE. For read we assume file matches system running the code.
1501 - Currently reserved, but unused labels
1502 - p: Pixel format
1503 - MXL: Each pixel of the image is written in sequence. DEFAULT VALUE.
1504 - PLN: Each channel of the *image* is written in sequence.
1505 - BIT: For bit-masks with 8 bits packed in a byte.
1506 - z: Compression
1507 - 000: No compression. DEFAULT VALUE.
1508 - ZLB: Zlib.
1509 - GZP: Gzip.
1510
1511 Two headers that both specify a 256x128 image with 3 unsigned 8-bit integer channels encoded little endian:
1512
1513 MJRRAW
1514 256x128y3c8bUNSsINTtLTLi00000000000000000000000000000000000000000000000000000000000000000000
1515
1516 MJRRAW
1517 0000000000000000256x0000000000000000128y000000000000000000000000003c00000000008bSGNsINTtLTLi
1518
1519 @param fileName The file name name to write data to
1520 @param rcConverter An rcConverter object instance
1521 @retval 0 The write was successful.
1522 @retval 1 Could not open file. */
1523 template <class rcConT> int writeRAWfile(std::string fileName, rcConT rcConverter);
1524 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1525 /** Simplified overload for writeRAWfile() that only requires the filename. */
1526 int writeRAWfile(std::string fileName);
1527 //@}
1528
1529 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1530 /** @name Boolean Clip Test Methods */
1531 //@{
1532 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1533 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1534 @param x The x coordinate of the point to test
1535 @param y The y coordinate of the point to test
1536 @return Returns true if the point would be clipped. */
1537 inline int isCliped(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1538 inline int isCliped(intCrdT x, intCrdT y) const { return ((x < 0) || (y < 0) || (x >= numPixX) || (y >= numPixY)); }
1539 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1540 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1541 @param x The x coordinate of the point to test
1542 @param y The y coordinate of the point to test
1543 @return Returns true if the point would be not be clipped. */
1544 inline int isOnCanvas(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1545 inline int isOnCanvas(intCrdT x, intCrdT y) const { return ((x >= 0) && (y >= 0) && (x < numPixX) && (y < numPixY)); }
1546 //@}
1547
1548 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1549 /** @name Coordinate Conversions. */
1550 //@{
1551 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1552 /** Convert real x coordinate to integral x coordinate
1553 @param x The real x coordinate value to be converted.
1554 @return The integer x coordinate corresponding to the given x coordinate */
1555 intCrdT real2intX(fltCrdT x) const;
1556 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1557 /** Convert real y coordinate to integral y coordinate
1558 @param y The real y coordinate value to be converted.
1559 @return The integer y coordinate corresponding to the given y coordinate */
1560 intCrdT real2intY(fltCrdT y) const;
1561 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1562 /** Convert integral x coordinate to real x coordinate
1563 @param x The integer x coordinate value to be converted.
1564 @return The real x coordinate corresponding to the given x coordinate */
1565 fltCrdT int2realX(intCrdT x);
1566 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1567 /** Convert integral y coordinate to real y coordinate
1568 @param y The integer y coordinate value to be converted.
1569 @return The real y coordinate corresponding to the given y coordinate */
1570 fltCrdT int2realY(intCrdT y);
1571 //@}
1572
1573 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1574 /** @name Coordinate Pair Conversions. */
1575 //@{
1576 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1577 /** Convert real x & y coordinates to integer x & y coordinates
1578 @param x The integer x coordinate value to be converted.
1579 @param y The integer y coordinate value to be converted.
1580 @return The real x & y coordinates corresponding to the given integer x & y coordinates */
1581 inline pointFltType int2real(intCrdT x, intCrdT y) { return point2d(int2realX(x), int2realY(y)); }
1582 /** Convert integer x & y coordinates to real x & y coordinates
1583 @param x The real x coordinate value to be converted.
1584 @param y The real y coordinate value to be converted.
1585 @return The integer x & y coordinates corresponding to the given real x & y coordinates */
1586 inline pointIntType real2int(intCrdT x, intCrdT y) { return point2d(real2intX(x), real2intY(y)); }
1587 //@}
1588
1589 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1590 /** @name Pixel Corner Coordinates.
1591
1592 @warning These functions are experimental! Functionality and API are likely to change in the future.
1593
1594 */
1595 //@{
1596 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1597 /** Given integer x & y coordinates, produce real x & y coordinates for one of the pixel's corners.
1598
1599 @warning This function is experimental! Functionality and API are likely to change in the future.
1600
1601 @param x The integer x coordinate value to be converted.
1602 @param y The integer y coordinate value to be converted.
1603 @param cornerX The integer x coordinate of the corner -- should be 0 or 1.
1604 @param cornerY The integer y coordinate of the corner -- should be 0 or 1.
1605 @return The real x & y coordinates corresponding to the requested corner */
1606 inline pointFltType int2corner(intCrdT x, intCrdT y, int cornerX, int cornerY) { return point2d(int2realX(x+cornerX)-pixWidX/2.0, int2realY(y+cornerY)-pixWidY/2.0); }
1607 /** Given integer x & y coordinates and a corner index, produce real x & y coordinates for one of the pixel's corners.
1608
1609 @warning This function is experimental! Functionality and API are likely to change in the future.
1610
1611 @param x The integer x coordinate value to be converted.
1612 @param y The integer y coordinate value to be converted.
1613 @param cornerIndex Corner index. 0 => (0, 0); 1 => (0, 1); 2 => (1, 0); 3 => (1, 1);
1614 @return The real x & y coordinates corresponding to the requested corner */
1615 inline pointFltType int2corner(intCrdT x, intCrdT y, int cornerIndex) { return int2corner(x, y, (cornerIndex >> 1), (cornerIndex & 1)); }
1616 //@}
1617
1618 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1619 /** @name Coordinate Delta Conversions. */
1620 //@{
1621 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1622 /** Convert real distance on the x coordinate axis to an integral distance
1623 @param x The real delta x to be converted
1624 @return integer delta x */
1625 inline intCrdT realDelta2intX(fltCrdT x) const { return static_cast<intCrdT>(static_cast<fltCrdT>(x)/pixWidX); }
1626 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1627 /** Convert real distance on the y coordinate axis to an integral distance
1628 @param y The real delta y to be converted
1629 @return integer delta y */
1630 inline intCrdT realDelta2intY(fltCrdT y) const { return static_cast<intCrdT>(static_cast<fltCrdT>(y)/pixWidY); }
1631 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1632 /** Convert integral distance on the x coordinate to a real distance
1633 @param x The real x coordinate value to be converted.
1634 @return The integer x coordinate corresponding to the given x coordinate */
1635 inline fltCrdT intDelta2realX(intCrdT x) const { return static_cast<fltCrdT>(x)*pixWidX; }
1636 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1637 /** Convert integral distance on the y coordinate to a real distance
1638 @param y real y coordinate value to be converted.
1639 @return The integer y coordinate corresponding to the given y coordinate */
1640 inline fltCrdT intDelta2realY(intCrdT y) const { return static_cast<fltCrdT>(y)*pixWidY; }
1641 //@}
1642
1643 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1644 /** @name Orientation of Real Coordinate Systems */
1645 //@{
1646 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1647 /** Get the real X axis orientation
1648 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1649 inline realAxisOrientation getRealAxOrientationX() { return realAxOrientationX; }
1650 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1651 /** Set the real X axis orientation
1652 @param orientation The orientation (INVERTED or NATURAL)*/
1653 inline void setRealAxOrientationX(realAxisOrientation orientation) { realAxOrientationX = orientation; }
1654 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1655 /** Get the real Y axis orientation
1656 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1657 inline realAxisOrientation getRealAxOrientationY() { return realAxOrientationX; }
1658 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1659 /** Set the real Y axis orientation
1660 @param orientation The orientation (INVERTED or NATURAL) */
1661 inline void setRealAxOrientationY(realAxisOrientation orientation) { realAxOrientationY = orientation; }
1662 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1663 /** Set the real axis orientation to default (NATURAL for both X and Y axes) */
1664 inline void setRealAxisDefaultOrientation() { setRealAxOrientationX(realAxisOrientation::NATURAL); setRealAxOrientationY(realAxisOrientation::NATURAL); }
1665 //@}
1666
1667 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1668 /** @name Drawing Mode */
1669 //@{
1670 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1671 /** Get the current drawing mode.
1672 @return The drawing mode */
1673 inline drawModeType getDrawMode() { return drawMode; }
1674 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1675 /** Set the current drawing mode
1676 NOOP if enableDrawModes is false.
1677 @param newDrawMode The drawing mode */
1678 inline void setDrawMode(drawModeType newDrawMode) { if (enableDrawModes) drawMode = newDrawMode; }
1679 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1680 /** Set the default draw mode */
1681 inline void setDefaultDrawMode() { setDrawMode(drawModeType::SET); }
1682 //@}
1683
1684 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1685 /** @name Orientation of Integer Coordinate Systems */
1686 //@{
1687 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1688 /** Get the integer X axis orientation
1689 @return NATURAL means increasing to the right. */
1690 inline intAxisOrientation getIntAxOrientationX() { return intAxOrientationX; }
1691 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1692 /** Is the integer X axis NATURAL?
1693 @return true means increasing to the right. */
1694 inline bool isIntAxOrientationNaturalX() { return (intAxOrientationX == intAxisOrientation::NATURAL); }
1695 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1696 /** Set the integer X axis orientation
1697 @param orientation The orientation (INVERTED or NATURAL) */
1698 inline void setIntAxOrientationX(intAxisOrientation orientation) { intAxOrientationX = orientation; }
1699 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1700 /** Get the integer Y axis orientation
1701 @return NATURAL means increasing in the upward direction. */
1702 inline bool isIntAxOrientationNaturalY() { return (intAxOrientationY == intAxisOrientation::NATURAL); }
1703 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1704 /** Is the integer Y axis orientation NATURAL?
1705 @return NATURAL means increasing in the upward direction. */
1706 inline intAxisOrientation getIntAxOrientationY() { return intAxOrientationY; }
1707 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1708 /** Set the integer Y axis orientation
1709 @param orientation The orientation (INVERTED or NATURAL) */
1710 inline void setIntAxOrientationY(intAxisOrientation orientation) { intAxOrientationY = orientation; }
1711 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1712 /** Set the integer axis orientation to default (NATURAL for both X and Y axes) */
1713 inline void setIntAxisDefaultOrientation() { setIntAxOrientationX(intAxisOrientation::NATURAL); setIntAxOrientationY(intAxisOrientation::NATURAL); }
1714 //@}
1715
1716 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1717 /** @name Accessor Methods */
1718 //@{
1719 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1720 /** @return The number of pixels in the x direction. */
1721 inline intCrdT getNumPixX() const { return numPixX; }
1722 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1723 /** @return The number of pixels in the y direction. */
1724 inline intCrdT getNumPixY() const { return numPixY; }
1725 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1726 /** Returns a pointer to the raw pixel store.
1727 This generally violates the ramCanvasTpl object interface; however, this may be required for performance.
1728 @return The number a pointer to the raw pixel store. */
1729 colorT *getPixels() { return pixels; }
1730 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1731 /** Return a clone (a copy) of the raw pixel store.
1732 This function copies the internal pixel store and returns a pointer to this copy.
1733 @return Pointer to a copy of the raw pixel store. */
1734 colorT *clonePixels();
1735 //@}
1736
1737 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1738 /** @name Real Coordinate Accessor Methods */
1739 //@{
1740 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1741 fltCrdT getMinRealX() { return minRealX; } //!< x coord of min (real coord)
1742 fltCrdT getMaxRealX() { return maxRealX; } //!< x coord of max (real coord)
1743 fltCrdT getMinRealY() { return minRealY; } //!< y coord of min (real coord)
1744 fltCrdT getMaxRealY() { return maxRealY; } //!< y coord of max (real coord)
1745 fltCrdT getPixWidX() { return pixWidX; } //!< Width of a pixel (real coord)
1746 fltCrdT getPixWidY() { return pixWidY; } //!< Height of a pixel (real coord)
1747 fltCrdT getCanvasWidX() { return canvasWidX; } //!< Width of the display (real coord)
1748 fltCrdT getCanvasWidY() { return canvasWidY; } //!< height of the display(real coord)
1749 fltCrdT getCanvasWidD() { return std::hypot(canvasWidX, canvasWidY); } //!< Width of the display (real coord)
1750 //@}
1751
1752 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1753 /** @name Pixel Value Accessor Methods */
1754 //@{
1755 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1756 /** Returns a copy of the color at the given coordinates */
1757 colorT getPxColor(intCrdT x, intCrdT y) const;
1758 inline colorT getPxColor(fltCrdT x, fltCrdT y) const { return getPxColor(real2intX(x), real2intY(y)); }
1759 inline colorT getPxColor(pointIntType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1760 inline colorT getPxColor(pointFltType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1761 //@}
1762
1763 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1764 /** @name Pixel Value Accessor with Interpolation Methods */
1765 //@{
1766 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1767 /** Returns the interpolated color value at the the given coordinates using the given interpolation method.
1768 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1769 @param y The y coordinate
1770 @param interpMethod The interpolation method (default: interpolationType::BILINEAR)
1771 @return Interpolated color value */
1772 colorT getPxColorInterpolate(double x, double y, interpolationType interpMethod = interpolationType::BILINEAR);
1773 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1774 /** Returns the bilinear interpolated color value at the the given coordinates.
1775 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1776 @param y The y coordinate
1777 @return Interpolated color value */
1778 colorT getPxColorInterpBLin(double x, double y);
1779 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1780 /** Returns the truncated interpolated color value at the the given coordinates.
1781 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1782 @param y The y coordinate
1783 @return Interpolated color value */
1784 colorT getPxColorInterpTrunc(double x, double y);
1785 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1786 /** Returns the nearest neighbor interpolated color value at the the given coordinates.
1787 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1788 @param y The y coordinate
1789 @return Interpolated color value */
1790 colorT getPxColorInterpNear(double x, double y);
1791 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1792 /** Returns the average 4 interpolated color value at the the given coordinates.
1793 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1794 @param y The y coordinate
1795 @return Interpolated color value */
1796 colorT getPxColorInterpAvg4(double x, double y);
1797 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1798 /** Returns the average 9 interpolated color value at the the given coordinates.
1799 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1800 @param y The y coordinate
1801 @return Interpolated color value */
1802 colorT getPxColorInterpAvg9(double x, double y);
1803 //@}
1804
1805 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1806 /** @name NC stands for No Checks and No Clipping */
1807 /** The functions here work in a similar way to the non-NC functions, but with no clipping or bounds checking. Thus, if an argument would cause
1808 something to be drawn beyond the bounds of the ramCanvasTpl, a core dump will most certainly result. The intent is to provide less overhead for
1809 very careful code that handles clipping and error checking by itself -- a good line drawing algorithm for example. */
1810 //@{
1811 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1812 /** Draw a point with no clipping or bounds checking.
1813 @param x The x coordinate of the point to be drawn
1814 @param y The y coordinate of the point to be drawn
1815 @param color The color to draw the point. */
1816 void drawPointNC(intCrdT x, intCrdT y, colorArgType color);
1817 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1818 /** Get the default point to the specified coordinates with no clipping or bounds checking.
1819 @param x The x coordinate of the point
1820 @param y The y coordinate of the point */
1821 inline colorT getPxColorNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1822 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1823 /** Returns a reference to the color object for the given pixel with no clipping or bounds checking.
1824 @param x The x coordinate of the point
1825 @param y The y coordinate of the point
1826 @return Reference to the color object associated with the specified point */
1827 inline colorT& getPxColorRefNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1828 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1829 /** Draw a horizontal line with no clipping or bounds checking.
1830 @param xMin The MINIMUM x coordinate of the line to be drawn
1831 @param xMax The MAXIMUM x coordinate of the line to be drawn
1832 @param yConst The y coordinate at which the line is to be drawn
1833 @param color The color to draw the line */
1834 inline void drawHorzLineNC(intCrdT xMin, intCrdT xMax, intCrdT yConst, colorArgType color) { for(intCrdT x=xMin;x<=xMax;x++) drawPointNC(x, yConst, color); }
1835 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1836 /** Draw a vertical line with no clipping or bounds checking.
1837 @param yMin The MINIMUM y coordinate of the line to be drawn
1838 @param yMax The MAXIMUM y coordinate of the line to be drawn
1839 @param xConst The x coordinate at which the line is to be drawn
1840 @param color The color to draw the line */
1841 inline void drawVertLineNC(intCrdT yMin, intCrdT yMax, intCrdT xConst, colorArgType color) { for(intCrdT y=yMin;y<=yMax;y++) drawPointNC(xConst, y, color); }
1842 //@}
1843
1844 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1845 /** @name S stands for Simple */
1846 //@{
1847 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1848 /** Draw a point without any special drawing options.
1849 It simply sets the pixel to the given color. In addition, no clipping or bounds checking is performed. Thus, if an argument would cause something
1850 to be drawn beyond the bounds of the ramCanvasTpl, a segfault will most certainly result. The intent is to provide a less overhead for very
1851 careful code that handles clipping and error checking and drawing options by itself -- an image filter algorithm for example. Note that enableDrawModes
1852 is ignored.
1853 @param x The x coordinate of the point
1854 @param y The y coordinate of the point
1855 @param color The color with which to draw the point */
1856 inline void drawPointS(intCrdT x, intCrdT y, colorArgType color) { pixels[numPixX * y + x] = color; }
1857 //@}
1858
1859 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1860 /** @name Canvas Level Colorization.
1861 These are tools designed to make things like escape time fractals very easy to create.
1862
1863 @warning These functions are experimental! Functionality and API are likely to change in the future.
1864
1865 */
1866 //@{
1867 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1868 void colorizeFltCanvas(std::function<colorT (fltCrdT, fltCrdT)> cFun);
1869 void colorizeFltCanvas(std::function<colorT (pointFltType)> cFun);
1870
1871 void colorizeIntCanvas(std::function<colorT (intCrdT, intCrdT)> cFun);
1872 void colorizeIntCanvas(std::function<colorT (pointIntType)> cFun);
1873 //@}
1874
1875
1876 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1877 /** @name Canvas Level Statistical Computation.
1878 */
1879 //@{
1880 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1881 intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
1882 intCrdT retCount = 0;
1883 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
1884 if(x1 > x2)
1885 std::swap(x1, x2);
1886 if(y1 > y2)
1887 std::swap(y1, y2);
1888 for(intCrdT y=y1;y<=y2;y++)
1889 for(intCrdT x=x1;x<=x2;x++)
1890 //if ( !(getPxColor(x, y).isBlack()))
1891 if ( !(getPxColorRefNC(x, y).isBlack()))
1892 retCount++;
1893 }
1894 return(retCount);
1895 }
1896 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1898 return statNumNonZeroPixels(0, 0, numPixX-1, numPixY-1);
1899 }
1900 //@}
1901 };
1902
1903 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1904 // Constructor
1905 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1906 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1908 newIntCoordsNC(-1, -1);
1909 newRealCoords(0.0, 0.0, 0.0, 0.0);
1910 pixels = NULL;
1911 pixelsE = NULL;
1912 setRealAxisDefaultOrientation();
1913 setIntAxisDefaultOrientation();
1914 setDefaultDrawMode();
1915 }
1916
1917////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1918 // Copy Constructor
1919 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1920 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1922 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1923 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1924 pixels = new colorT[theCanvas.numPixX * theCanvas.numPixY];
1925 pixelsE = pixels + (theCanvas.numPixX * theCanvas.numPixY);
1926 realAxOrientationX = theCanvas.realAxOrientationX;
1927 realAxOrientationY = theCanvas.realAxOrientationY;
1928 intAxOrientationX = theCanvas.intAxOrientationX;
1929 intAxOrientationY = theCanvas.intAxOrientationY;
1930 drawMode = theCanvas.drawMode;
1931 for(intCrdT y=0; y<numPixY; y++)
1932 for(intCrdT x=0; x<numPixX; x++)
1933 getPxColorRefNC(x, y) = theCanvas.getPxColorRefNC(x, y);
1934 }
1935
1936////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1937// Move constructor
1938 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1939 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1941 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1942 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1943 realAxOrientationX = theCanvas.realAxOrientationX;
1944 realAxOrientationY = theCanvas.realAxOrientationY;
1945 intAxOrientationX = theCanvas.intAxOrientationX;
1946 intAxOrientationY = theCanvas.intAxOrientationY;
1947 drawMode = theCanvas.drawMode;
1948 pixels = theCanvas.pixels;
1949 pixelsE = theCanvas.pixelsE;
1950 }
1951
1952////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1953// Move assignment operator
1954 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1955 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1958 if (this != &theCanvas) {
1959 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1960 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1961 realAxOrientationX = theCanvas.realAxOrientationX;
1962 realAxOrientationY = theCanvas.realAxOrientationY;
1963 intAxOrientationX = theCanvas.intAxOrientationX;
1964 intAxOrientationY = theCanvas.intAxOrientationY;
1965 drawMode = theCanvas.drawMode;
1966 pixels = theCanvas.pixels;
1967 pixelsE = theCanvas.pixelsE;
1968 }
1969 return *this;
1970 }
1971
1972////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1973 // Normal Constructor
1974 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1975 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1976 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
1977 newIntCoordsNC(numPixX_p, numPixY_p);
1978 newRealCoords(minRealX_p, maxRealX_p, minRealY_p, maxRealY_p);
1979 pixels = new colorT[numPixX * numPixY];
1980 pixelsE = pixels + (numPixX * numPixY);
1981 setRealAxisDefaultOrientation();
1982 setIntAxisDefaultOrientation();
1983 setDefaultDrawMode();
1984 clrCanvasToBlack();
1985 }
1986
1987////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1988 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1989 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1991 if(pixels != NULL) {
1992 delete[] pixels;
1993 pixels = NULL;
1994 }
1995 }
1996
1997////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1998 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1999 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2000 inline void
2002 if(numPixX_p > intCrdMax) {
2003 throw std::invalid_argument("newIntCoordsNC: numPixX_p argument too large.");
2004 } else if (numPixY_p > intCrdMax) {
2005 throw std::invalid_argument("newIntCoordsNC: numPixY_p argument too large.");
2006 } else {
2007 numPix = numPixX_p * numPixY_p;;
2008 numPixX = numPixX_p;
2009 numPixY = numPixY_p;
2010 }
2011 }
2012
2013////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2014 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2015 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2016 inline void
2017 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
2018 if(minRealX_p > maxRealX_p) {
2019 throw std::invalid_argument("newRealCoords: minRealX_p > maxRealX_p.");
2020 } else if (minRealY_p > maxRealY_p) {
2021 throw std::invalid_argument("newRealCoords: minRealY_p > maxRealY_p.");
2022 } else {
2023 minRealX = minRealX_p;
2024 maxRealX = maxRealX_p;
2025 minRealY = minRealY_p;
2026 maxRealY = maxRealY_p;
2027 updRealCoords();
2028 }
2029 }
2030
2031////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2032 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2033 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2034 inline void
2036 canvasWidX = maxRealX - minRealX;
2037 canvasWidY = maxRealY - minRealY;
2038 pixWidX = (numPixX == 0 ? 0 : canvasWidX / numPixX); // This will cause /0 later if anyone tries to use a coordinate conversion
2039 pixWidY = (numPixY == 0 ? 0 : canvasWidY / numPixY); // This will cause /0 later if anyone tries to use a coordinate conversion
2040 }
2041
2042////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2043 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2044 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2045 inline void
2047 for(intCrdT y=0; y<numPixY; y++)
2048 for(intCrdT x=0; x<numPixX; x++)
2049 getPxColorRefNC(x, y).setChanToMin(chan);
2050 }
2051
2052////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2053 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2054 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2055 inline void
2057 for(intCrdT y=0; y<numPixY; y++)
2058 for(intCrdT x=0; x<numPixX; x++)
2059 getPxColorRefNC(x, y).setChanToMax(chan);
2060 }
2061
2062////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2063 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2064 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2065 inline void
2067 ////// Diffrent ways to do it -- unless otherwise noted, all of them are about the same performance with GCC if colorT has a fast mask
2068
2069 //// Use std:memset
2070 // std::memset((void*)pixels, 0, numPix*sizeof(colorT));
2071
2072 //// Use std::fill
2073 // colorT black;
2074 // black.setToBlack();
2075 // std::fill(pixels, pixelsE, black);
2076
2077 //// Loop over pixel array
2078 // for(colorT* p=pixels; p<pixelsE; p++)
2079 // p->setToBlack();
2080
2081 //// loop over x & y coordinates
2082 for(intCrdT y=0; y<numPixY; y++)
2083 for(intCrdT x=0; x<numPixX; x++)
2084 getPxColorRefNC(x, y).setToBlack();
2085
2086 //// Call clrCanvas with black (this one is *way* slower)
2087 // clrCanvas(colorT(colorCornerEnum::BLACK));
2088 }
2089
2090////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2091 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2092 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2093 inline void
2095 for(intCrdT y=0; y<numPixY; y++)
2096 for(intCrdT x=0; x<numPixX; x++)
2097 getPxColorRefNC(x, y).setToWhite();
2098 }
2099
2100////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2101 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2102 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2103 inline void
2107
2108////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2109 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2110 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2111 inline void
2113 for(intCrdT y=0; y<numPixY; y++)
2114 for(intCrdT x=0; x<numPixX; x++)
2115 drawPointS(x, y, color);
2116 }
2117
2118////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2119 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2120 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2121 void
2123 colorChanType cmin = colorT::maxChanVal;
2124 colorChanType cmax = colorT::minChanVal;
2125 for(intCrdT y=0;y<numPixY;y++) {
2126 for(intCrdT x=0;x<numPixX;x++) {
2127 colorT daColor = getPxColorNC(x, y);
2128 colorChanType curMin = daColor.getMinC();
2129 colorChanType curMax = daColor.getMaxC();
2130 if(curMax > cmax)
2131 cmax = curMax;
2132 if(curMin < cmin)
2133 cmin = curMin;
2134 }
2135 }
2136 if(cmax-cmin > 0) {
2137 double c = 1.0 * static_cast<double>(colorT::maxChanVal-colorT::minChanVal) / static_cast<double>(cmax-cmin);
2138 double b = static_cast<double>(colorT::maxChanVal) - 1.0 * c * static_cast<double>(cmax);
2139 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScale, c, b);
2140 }
2141 }
2142
2143////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2144 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2145 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2146 void
2148 colorT cmin; cmin.setChans(cmin.maxChanVal);
2149 colorT cmax; cmax.setChans(cmin.minChanVal);
2150 for(intCrdT y=0;y<numPixY;y++) {
2151 for(intCrdT x=0;x<numPixX;x++) {
2152 colorT daColor = getPxColorNC(x, y);
2153 cmin.tfrmMin(daColor);
2154 cmax.tfrmMax(daColor);
2155 }
2156 }
2157 colorChanType absCompMin = cmin.getMinC();
2158 colorChanType absCompMax = cmax.getMaxC();
2159 if(absCompMax-absCompMin > 0) {
2160 double rc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getRed()-cmin.getRed());
2161 double rb = cmin.maxChanVal - 1.0*rc*cmax.getRed();
2162 double gc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getGreen()-cmin.getGreen());
2163 double gb = cmin.maxChanVal - 1.0*gc*cmax.getGreen();
2164 double bc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getBlue()-cmin.getBlue());
2165 double bb = cmin.maxChanVal - 1.0*bc*cmax.getBlue();
2166 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScaleRGB, rc, rb, gc, gb, bc, bb);
2167 }
2168 }
2169
2170////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2171 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2172 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2173 inline void
2175 for(intCrdT y=0; y<numPixY; y++)
2176 for(intCrdT x=0; x<numPixX; x++)
2177 (getPxColorRefNC(x, y).*HPT)();
2178 }
2179
2180////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2181 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2182 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2183 inline void
2185 for(intCrdT y=0; y<numPixY; y++)
2186 for(intCrdT x=0; x<numPixX; x++)
2187 (getPxColorRefNC(x, y).*HPT)(arg1);
2188 }
2189
2190////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2191 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2192 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2193 inline void
2194 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT arg1, colorT arg2) {
2195 for(intCrdT y=0; y<numPixY; y++)
2196 for(intCrdT x=0; x<numPixX; x++)
2197 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2198 }
2199
2200////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2201 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2202 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2203 inline void
2204 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3) {
2205 for(intCrdT y=0; y<numPixY; y++)
2206 for(intCrdT x=0; x<numPixX; x++)
2207 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2208 }
2209
2210////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2211 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2212 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2213 inline void
2214 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3, colorT arg4) {
2215 for(intCrdT y=0; y<numPixY; y++)
2216 for(intCrdT x=0; x<numPixX; x++)
2217 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2218 }
2219
2220////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2221 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2222 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2223 inline void
2225 for(intCrdT y=0; y<numPixY; y++)
2226 for(intCrdT x=0; x<numPixX; x++)
2227 (getPxColorRefNC(x, y).*HPT)(arg1);
2228 }
2229
2230////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2231 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2232 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2233 inline void
2234 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int arg1, int arg2) {
2235 for(intCrdT y=0; y<numPixY; y++)
2236 for(intCrdT x=0; x<numPixX; x++)
2237 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2238 }
2239
2240////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2241 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2242 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2243 inline void
2244 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int arg1, int arg2, int arg3) {
2245 for(intCrdT y=0; y<numPixY; y++)
2246 for(intCrdT x=0; x<numPixX; x++)
2247 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2248 }
2249
2250////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2251 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2252 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2253 inline void
2254 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int arg1, int arg2, int arg3, int arg4) {
2255 for(intCrdT y=0; y<numPixY; y++)
2256 for(intCrdT x=0; x<numPixX; x++)
2257 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2258 }
2259
2260////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2261 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2262 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2263 inline void
2265 for(intCrdT y=0; y<numPixY; y++)
2266 for(intCrdT x=0; x<numPixX; x++)
2267 (getPxColorRefNC(x, y).*HPT)(arg1);
2268 }
2269
2270////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2271 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2272 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2273 inline void
2274 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double arg1, double arg2) {
2275 for(intCrdT y=0; y<numPixY; y++)
2276 for(intCrdT x=0; x<numPixX; x++)
2277 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2278 }
2279
2280////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2281 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2282 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2283 inline void
2284 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double arg1, double arg2, double arg3) {
2285 for(intCrdT y=0; y<numPixY; y++)
2286 for(intCrdT x=0; x<numPixX; x++)
2287 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2288 }
2289
2290////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2291 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2292 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2293 inline void
2294 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double),
2295 double arg1, double arg2, double arg3, double arg4) {
2296 for(intCrdT y=0; y<numPixY; y++)
2297 for(intCrdT x=0; x<numPixX; x++)
2298 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2299 }
2300
2301////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2302 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2303 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2304 inline void
2305 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double),
2306 double arg1, double arg2, double arg3, double arg4, double arg5) {
2307 for(intCrdT y=0; y<numPixY; y++)
2308 for(intCrdT x=0; x<numPixX; x++)
2309 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5);
2310 }
2311
2312////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2313 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2314 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2315 inline void ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double),
2316 double arg1, double arg2, double arg3, double arg4, double arg5, double arg6) {
2317 for(intCrdT y=0; y<numPixY; y++)
2318 for(intCrdT x=0; x<numPixX; x++)
2319 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5, arg6);
2320 }
2321
2322////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2323 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2324 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2326 const ramCanvasTpl &theCanvas,
2327 intCrdT trgX, intCrdT trgY,
2328 intCrdT wide, intCrdT tall,
2329 intCrdT srcX, intCrdT srcY) {
2330 // Figure out real default width
2331 if(wide < 0)
2332 wide = numPixX-trgX;
2333
2334 // Make sure wide is not wider than current canvas.
2335 if(wide > (numPixX-srcX))
2336 wide = theCanvas.getNumPixX()-srcX;
2337
2338 // Make sure wide is not wider than given canvas.
2339 if(wide > (theCanvas.getNumPixX()-srcX))
2340 wide = theCanvas.getNumPixX()-srcX;
2341
2342 // Figure out real default tall
2343 if(tall < 0)
2344 tall = numPixY-srcY;
2345
2346 // Make sure tall is not taller than current canvas.
2347 if(tall > (numPixY-srcY))
2348 tall = numPixY-srcY;
2349
2350 // Make sure tall is not taller than given canvas.
2351 if(tall > (theCanvas.getNumPixY()-srcY))
2352 tall = theCanvas.getNumPixY()-srcY;
2353
2354 intCrdT xMax = trgX+wide;
2355 intCrdT yMax = trgY+tall;
2356 for(intCrdT y=trgY, ys=srcY; y<yMax; y++, ys++)
2357 for(intCrdT x=trgX, xs=srcX; x<xMax; x++, xs++)
2358 (getPxColorRefNC(x, y).*HPT)(theCanvas.getPxColor(xs, ys));
2359 }
2360
2361////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2362 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2363 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2364 void
2365 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
2366 moveTo(x2, y2); // Do this first
2367 intCrdT x, y;
2368 if(y1 == y2) { // slope = 0
2369 if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
2370 return;
2371 if(x1 > x2) // . Fix point ordering
2372 std::swap(x1, x2);
2373 if(x1 < 0) // . Clip left
2374 x1 = 0;
2375 if(x2 >= numPixX) // . Clip right
2376 x2 = numPixX - 1;
2377 drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
2378 } else if(x1 == x2) { // slope = infinity
2379 if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
2380 return;
2381 if(y1 > y2) // . Fix point ordering
2382 std::swap(y1, y2);
2383 if(y1 < 0) // . Clip top
2384 y1 = 0;
2385 if(y2 >= numPixY) // . Clip bottom
2386 y2 = numPixY - 1;
2387 drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
2388 } else { // Slope is not infinity or 0...
2389 int dx, dy;
2390 if(x1 > x2) { // . Fix point ordering
2391 std::swap(x1, x2);
2392 std::swap(y1, y2);
2393 }
2394 dx = x2 - x1; // . Compute the slope
2395 dy = y2 - y1;
2396 if(dx == dy) { // . Slope = 1
2397 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
2398 return;
2399 if(x1 < 0) { // .. Clip left
2400 y1 = y1 - x1;
2401 x1 = 0;
2402 }
2403 if(y1 < 0) { // .. Clip top
2404 x1 = x1 - y1;
2405 y1 = 0;
2406 }
2407 if(x2 >= numPixX) { // .. Clip right
2408 y2 = y2 - (x2 - numPixX) - 1;
2409 x2 = numPixX - 1;
2410 }
2411 if(y2 >= numPixY) { // .. Clip bottom
2412 x2 = x2 - (y2 - numPixY) - 1;
2413 y2 = numPixY - 1;
2414 }
2415 for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
2416 drawPointNC(x, y, color);
2417 } else if(dx == -dy) { // . Slope = -1
2418 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
2419 return;
2420 if(x1 < 0) { // .. Clip left
2421 y1 = y1 + x1;
2422 x1 = 0;
2423 }
2424 if(x2 >= numPixX) { // .. Clip right
2425 y2 = y2 + (x2 - (numPixX - 1));
2426 x2 = numPixX - 1;
2427 }
2428 if(y2 < 0) { // .. Clip top
2429 x2 = x2 + y2;
2430 y2 = 0;
2431 }
2432 if(y1 >= numPixY) { // .. Clip bottom
2433 x1 = x1 + (y1 - (numPixY - 1));
2434 y1 = numPixY - 1;
2435 }
2436 for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
2437 drawPointNC(x, y, color);
2438 } else { // . Slope != 1, -1, 0, \infinity
2439 int s, dx2, dy2;
2440 dx2 = 2*dx;
2441 dy2 = 2*dy;
2442 if(dy > 0) { // .. Positive Slope
2443 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
2444 return;
2445 if(x1 < 0) { // ... Clip left
2446 y1 = (int)(1.0*y1-x1*dy/dx);
2447 x1 = 0;
2448 }
2449 if(y1 < 0) { // ... Clip top
2450 x1 = (int)(1.0*x1-y1*dx/dy);
2451 y1 = 0;
2452 }
2453 if(x2 >= numPixX) { // ... Clip right
2454 y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
2455 x2 = numPixX - 1;
2456 }
2457 if(y2 >= numPixY) { // ... Clip bottom
2458 x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
2459 y2 = numPixY - 1;
2460 }
2461// MJR TODO NOTE drawLine: We use drawPoint instead of drawPointNC, can we make an off canvas decesion instead? Similar case down below.
2462 if(dx > dy) { // ... 0 < Slope < 1
2463 s = dy2 - dx;
2464 x=x1;
2465 y=y1;
2466 while(x<=x2) { // .... Draw Line
2467 drawPoint(x, y, color);
2468 if(s < 0) {
2469 s += dy2;
2470 } else {
2471 y++;
2472 s += dy2 - dx2;
2473 }
2474 x++;
2475 }
2476 } else { // ... 1 < Slope < infinity
2477 s = dy - dx2;
2478 x=x1;
2479 y=y1;
2480 while(y<=y2) { // .... Draw Line
2481 drawPoint(x, y, color);
2482 if(s > 0) {
2483 s -= dx2;
2484 } else {
2485 x++;
2486 s += dy2 - dx2;
2487 }
2488 y++;
2489 }
2490 }
2491 } else { // .. Negative Slope
2492 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
2493 return;
2494 if(x1 < 0) { // ... Clip left
2495 y1 = (int)(1.0*y1-x1*dy/dx);
2496 x1 = 0;
2497 }
2498 if(y2 < 0) { // ... Clip top
2499 x2 = (int)(1.0*x2-y2*dx/dy);
2500 y2 = 0;
2501 }
2502 if(x2 >= numPixX) { // ... Clip right
2503 y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
2504 x2 = numPixX - 1;
2505 }
2506 if(y1 >= numPixY) { // ... Clip bottom
2507 x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
2508 y1 = numPixY - 1;
2509 }
2510 if(dx > -dy) { // ... 0 > Slope > -infinity
2511 s = dy2 + dx;
2512 x=x1;
2513 y=y1;
2514 while(x<=x2) { // .... Draw Line
2515 drawPoint(x, y, color);
2516 if(s > 0) {
2517 s += dy2;
2518 } else {
2519 y--;
2520 s += dy2 + dx2;
2521 }
2522 x++;
2523 }
2524 } else { // ... -1 > Slope > -inf
2525 s = dy + dx2;
2526 x=x1;
2527 y=y1;
2528 while(y>=y2) { // .... Draw Line
2529 drawPoint(x, y, color);
2530 if(s < 0) {
2531 s += dx2;
2532 } else {
2533 x++;
2534 s += dy2 + dx2;
2535 }
2536 y--;
2537 }
2538 }
2539 }
2540 }
2541 }
2542 }
2543
2544////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2545 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2546 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2547 void
2549 newIntCoordsNC(-1, -1);
2550 if(pixels != NULL) {
2551 delete[] pixels;
2552 pixels=NULL;
2553 pixelsE=NULL;
2554 }
2555 }
2556
2557////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2558 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2559 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2560 void
2561 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY) {
2562 freeCanvas();
2563 newIntCoordsNC(new_numPixX, new_numPixY);
2564 updRealCoords();
2565 if(new_pixels != NULL)
2566 pixels = new_pixels;
2567 if(pixels == NULL)
2568 pixelsE = NULL;
2569 else
2570 pixelsE = pixels+(new_numPixX * new_numPixY);
2571 }
2572
2573////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2574 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2575 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2576 void
2578 if((numPixX_p<=0) || (numPixY_p<=0)) {
2579 freeCanvas();
2580 } else {
2581 if( (numPixX_p!=numPixX) || (numPixY_p!=numPixY) ) {
2582 colorT *new_pixels = new colorT[numPixX_p * numPixY_p];
2583 rePointPixels(new_pixels, numPixX_p, numPixY_p);
2584 } else {
2585 // Don't really do anything as the new size is the same as the old size...
2586 }
2587 }
2588 }
2589
2590////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2591 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2592 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2593 void
2595 reallocCanvas(new_numPixX_p, new_numPixY_p);
2596 }
2597
2598////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2599 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2600 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2601 void
2602 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1, intCrdT y1, colorArgType color) {
2603 if( (new_numPixX_p != numPixX) || (new_numPixY_p != numPixY) ) {
2604
2605 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2606
2607 // Fill it up with the default color. Should only draw the ones that need it, but computers are fast...
2608 for(intCrdT y=0;y<new_numPixY_p;y++)
2609 for(intCrdT x=0;x<new_numPixX_p;x++)
2610 new_pixels[new_numPixX_p * (y) + (x)] = color;
2611
2612 intCrdT yMax = std::min(numPixY+y1, new_numPixY_p);
2613 intCrdT xMax = std::min(numPixX+x1, new_numPixX_p);
2614
2615 // Copy the old image to the new space.
2616 if ((x1 < new_numPixX_p) && (y1 < new_numPixY_p))
2617 for(intCrdT y=y1;y<yMax;y++)
2618 for(intCrdT x=x1;x<xMax;x++)
2619 new_pixels[new_numPixX_p * (y) + (x)] = getPxColor(x-x1, y-y1);
2620
2621 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2622 }
2623 }
2624
2625////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2626 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2627 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2628 void
2629 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
2630 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
2631 if(x1 > x2)
2632 std::swap(x1, x2);
2633 if(y1 > y2)
2634 std::swap(y1, y2);
2635 intCrdT xp, yp, x, y;
2636 intCrdT new_numPixX_p = x2-x1+1;
2637 intCrdT new_numPixY_p = y2-y1+1;
2638 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2639
2640 // Copy the old image to the new space.
2641 for(y=y1,yp=0;y<=y2;y++,yp++)
2642 for(x=x1,xp=0;x<=x2;x++,xp++)
2643 new_pixels[new_numPixX_p * yp + xp] = getPxColor(x, y);
2644
2645 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2646 }
2647 }
2648
2649////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2650 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2651 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2652 void
2654 for(intCrdT y=0; y<numPixY/2; y++)
2655 for(intCrdT x=0; x<numPixX; x++) {
2656 colorT aColor = getPxColor(x, numPixY-y-1);
2657 drawPointNC(x, numPixY-y-1, getPxColor(x, y));
2658 drawPointNC(x, y, aColor);
2659 }
2660 }
2661
2662////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2663 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2664 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2665 void
2667 for(intCrdT x=0; x<numPixX/2; x++)
2668 for(intCrdT y=0; y<numPixY; y++) {
2669 colorT aColor = getPxColor(numPixX-x-1, y);
2670 drawPointNC(numPixX-x-1, y, getPxColor(x, y));
2671 drawPointNC(x, y, aColor);
2672 }
2673 }
2674
2675////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2676 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2677 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2678 void
2680 intCrdT new_numPixX_p = numPixY;
2681 intCrdT new_numPixY_p = numPixX;
2682 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2683 for(intCrdT y=0; y<numPixY; y++)
2684 for(intCrdT x=0; x<numPixX; x++)
2685 new_pixels[new_numPixX_p * (x/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2686 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2687 }
2688
2689////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2690 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2691 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2692 void
2694 intCrdT new_numPixX_p = numPixY;
2695 intCrdT new_numPixY_p = numPixX;
2696 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2697 for(intCrdT y=0; y<numPixY; y++)
2698 for(intCrdT x=0; x<numPixX; x++)
2699 new_pixels[new_numPixX_p * (numPixX-x-1/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2700 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2701 }
2702
2703////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2704 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2705 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2706 void
2708 intCrdT new_numPixX_p = numPixY;
2709 intCrdT new_numPixY_p = numPixX;
2710 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2711 for(intCrdT y=0; y<numPixY; y++)
2712 for(intCrdT x=0; x<numPixX; x++)
2713 new_pixels[new_numPixX_p * (x/*y-crd*/) + (numPixY-y-1/*x-crd*/)] = getPxColor(x, y);
2714 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2715 }
2716
2717////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2718 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2719 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2720 void
2722 intCrdT new_numPixX_p = numPixX;
2723 intCrdT new_numPixY_p = numPixY;
2724 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2725 for(intCrdT y=0; y<numPixY; y++)
2726 for(intCrdT x=0; x<numPixX; x++)
2727 new_pixels[new_numPixX_p * (numPixY-y-1/*y-crd*/) + (numPixX-x-1/*x-crd*/)] = getPxColor(x, y);
2728 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2729 }
2730
2731////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2732 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2733 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2736 unsigned int endiannessProbe = 1;
2737 if(((char *)&endiannessProbe)[0]) {
2738 return endianType::LITTLE;
2739 } else {
2740 return endianType::BIG;
2741 }
2742 }
2743
2744////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2745 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2746 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2747 inline void
2750 int numBytes,
2751 uint64_t data) {
2752 if(numBytes>0) {
2753 if (numBytes == 1) {
2754 uint8_t tmp = (data & 0xff);
2755 oStream.write((const char *)&tmp, 1);
2756 } else {
2757 if (numBytes<9) {
2758 endianType endiannessToUse = (endianness == endianType::AUTO ? platformEndianness() : endianness);
2759 if(endiannessToUse == endianType::LITTLE) {
2760 for(int curByte=0; curByte<numBytes; curByte++) {
2761 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2762 oStream.write((const char *)&tmp, 1);
2763 }
2764 } else {
2765 for(int curByte=(numBytes-1); curByte>=0; curByte--) {
2766 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2767 oStream.write((const char *)&tmp, 1);
2768 }
2769 }
2770 }
2771 }
2772 }
2773 }
2774
2775////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2776 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2777 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2778 void
2780 for(intCrdT yi=0;yi<numPixY;yi++) {
2781 for(intCrdT xi=0;xi<numPixX;xi++) {
2782 fltCrdT xf = int2realX(xi);
2783 fltCrdT yf = int2realY(yi);
2784 colorT aColor = cFun(xf, yf);
2785 drawPoint(xi, yi, aColor);
2786 }
2787 }
2788 }
2789
2790////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2791 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2792 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2793 void
2795 for(intCrdT yi=0;yi<numPixY;yi++) {
2796 for(intCrdT xi=0;xi<numPixX;xi++) {
2797 pointFltType xyPt(int2realX(xi), int2realY(yi));
2798 colorT aColor = cFun(xyPt);
2799 drawPoint(xi, yi, aColor);
2800 }
2801 }
2802 }
2803
2804////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2805 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2806 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2807 void
2809 for(intCrdT yi=0;yi<numPixY;yi++) {
2810 for(intCrdT xi=0;xi<numPixX;xi++) {
2811 colorT aColor = cFun(xi, yi);
2812 drawPoint(xi, yi, aColor);
2813 }
2814 }
2815 }
2816
2817////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2818 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2819 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2820 void
2822 for(intCrdT yi=0;yi<numPixY;yi++) {
2823 for(intCrdT xi=0;xi<numPixX;xi++) {
2824 pointIntType xyPt(xi, yi);
2825 colorT aColor = cFun(xyPt);
2826 drawPoint(xi, yi, aColor);
2827 }
2828 }
2829 }
2830
2831////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2832 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2833 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2834 inline int
2836
2837 std::ofstream outStream;
2838 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2839 if (outStream.is_open())
2840 outStream.imbue(std::locale::classic());
2841 else
2842 return 1;
2843
2844 if(numPixX < 1) // too skinny
2845 return 6;
2846 if(numPixX > 0xffff) // too wide
2847 return 7;
2848 if(numPixY < 1) // too short
2849 return 8;
2850 if(numPixY > 0xffff) // too tall
2851 return 9;
2852
2853 /* Write header */
2854 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // id length
2855 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colourmaptype
2856 writeUIntToStream(outStream, endianType::LITTLE, 1, 2); // datatypecode: 2 == Truecolor RGB 8-bit, 3 == Monochrome
2857 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit colourmaporigin
2858 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // colurmaplength
2859 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colormapdepth
2860 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit x_origin
2861 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit y_origon
2862 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixX); // Width
2863 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixY); // Height
2864 writeUIntToStream(outStream, endianType::LITTLE, 1, 24); // bits per pixel
2865 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // imagedescriptor
2866
2867 /* Write data */
2868 intCrdT x, y;
2869 /* Normally I would not resort to such trickery; however, this is an exception. The following for loop is equivalent to switching between the two forms
2870 "for(y=(numPixY-1); y>=0; y--)" and "for(y=0; y<numPixY; y++)". */
2871 bool yNat = isIntAxOrientationNaturalY();
2872 bool xNat = isIntAxOrientationNaturalX();
2873 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
2874 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
2875 colorT aColor = getPxColorRefNC(x, y);
2876 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestBlueChan()));
2877 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestGreenChan()));
2878 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestRedChan()));
2879 }
2880 }
2881 return 0;
2882 }
2883
2884////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2885 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2886 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2887 inline int
2890 return writeRAWfile(fileName, tmp);
2891 }
2892
2893////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2894 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2895 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2896 template <class rcConT>
2897 inline int
2899
2900 std::ofstream outStream;
2901 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2902 if (outStream.is_open())
2903 outStream.imbue(std::locale::classic());
2904 else
2905 return 1;
2906
2907 outStream << "MJRRAW\n"; // 7 7
2908 outStream << std::setw(19) << std::setfill('0') << rcConverter.getNumPixX() << "x"; // 20 27
2909 outStream << std::setw(19) << std::setfill('0') << rcConverter.getNumPixY() << "y"; // 20 47
2910 outStream << std::setw(27) << std::setfill('0') << rcConT::colorType::channelCount << "c"; // 28 75
2911 outStream << std::setw(11) << std::setfill('0') << rcConT::colorType::bitsPerChan << "b"; // 12 87
2912 outStream << (rcConT::colorType::chanIsUnsigned ? "UNS" : "SGN") << "s"; // 4 91
2913 outStream << (rcConT::colorType::chanIsInt ? "INT" : "FLT") << "t"; // 4 95
2914 outStream << (platformEndianness() == endianType::LITTLE ? "LTL" : "BIG") << "i"; // 4 99
2915 outStream << "\n"; // 1 100
2916
2917 intCrdT x, y;
2918 /* Normally I would not resort to such trickery; however, this is an exception. The following for loop is equivalent to switching between the two forms
2919 "for(y=(rcConverter.getNumPixY()-1); y>=0; y--)" and "for(y=0; y<rcConverter.getNumPixY(); y++)". */
2920 bool yNat = !(rcConverter.isIntAxOrientationNaturalY());
2921 bool xNat = rcConverter.isIntAxOrientationNaturalX();
2922 for((yNat?y=0:y=(rcConverter.getNumPixY()-1)); (yNat?y<rcConverter.getNumPixY():y>=0); (yNat?y++:y--)) {
2923 for((xNat?x=0:x=(rcConverter.getNumPixX()-1)); (xNat?x<rcConverter.getNumPixX():x>=0); (xNat?x++:x--)) {
2924 typename rcConT::colorType aColor = rcConverter.getPxColorNC(x, y);
2925 for(int c=0; c<aColor.channelCount; c++) {
2926 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
2927 outStream.write((const char *)&aChanValue, sizeof(colorChanType));
2928 }
2929 }
2930 }
2931 return 0;
2932 }
2933
2934////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2935 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2936 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2937 inline int
2940 return writeTIFFfile(fileName, tmp, markAlpha);
2941}
2942
2943////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2944 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2945 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2946 template <class rcConT>
2947 inline int
2948 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::writeTIFFfile(std::string fileName, rcConT rcConverter, bool markAlpha) {
2949
2950 if(rcConT::colorType::bitsPerChan < 8) // channels too thin
2951 return 2;
2952 if(rcConT::colorType::bitsPerChan > 0xffff) // channels too fat
2953 return 3;
2954 if(rcConT::colorType::channelCount < 1) // too few channels
2955 return 4;
2956 if(rcConT::colorType::channelCount > 0xffff) // too many channels
2957 return 5;
2958 if(rcConverter.getNumPixX() < 1) // too skinny
2959 return 6;
2960 if(rcConverter.getNumPixX() > 0x7fffffff) // too wide
2961 return 7;
2962 if(rcConverter.getNumPixY() < 1) // too short
2963 return 8;
2964 if(rcConverter.getNumPixY() > 0x7fffffff) // too tall
2965 return 9;
2966 unsigned long bytesPerRow = rcConverter.getNumPixX() * rcConT::colorType::bitsPerChan / 8ul * rcConT::colorType::channelCount;
2967 if(bytesPerRow > 0xffffffff) // rows too big
2968 return 10;
2969 if(bytesPerRow * rcConverter.getNumPixY() > 0xfffffffff) // image too big
2970 return 11;
2971
2972 // //grep -E '^#define[[:space:]]+(TIFF_BIGENDIAN|TIFF_LITTLEENDIAN|PHOTOMETRIC_RGB|PHOTOMETRIC_MINISBLACK|PLANARCONFIG_CONTIG|ORIENTATION_TOPLEFT|RESUNIT_NONE|SAMPLEFORMAT_UINT|SAMPLEFORMAT_IEEEFP)' /mingw64/include/tiff.h
2973 const uint16_t tcTIFF_BIGENDIAN = 0x4d4d; /* Magic number for big endian */
2974 const uint16_t tcTIFF_LITTLEENDIAN = 0x4949; /* Magic number for little endian */
2975 const uint16_t tcPHOTOMETRIC_MINISBLACK = 1; /* min value is black */
2976 const uint16_t tcPHOTOMETRIC_RGB = 2; /* RGB color model */
2977 const uint16_t tcORIENTATION_TOPLEFT = 1; /* row 0 top, col 0 lhs */
2978 const uint16_t tcPLANARCONFIG_CONTIG = 1; /* single image plane */
2979 const uint16_t tcRESUNIT_NONE = 1; /* no meaningful units */
2980 const uint16_t tcSAMPLEFORMAT_UINT = 1; /* !unsigned integer data */
2981 const uint16_t tcSAMPLEFORMAT_IEEEFP = 3; /* !IEEE floating point data */
2982
2983 // //grep -E '^#define[[:space:]]+TIFFTAG_(IMAGEWIDTH|IMAGELENGTH|BITSPERSAMPLE|PHOTOMETRIC|ORIENTATION|SAMPLESPERPIXEL|PLANARCONFIG|RESOLUTIONUNIT|COMPRESSION|STRIPOFFSETS|ROWSPERSTRIP|STRIPBYTECOUNTS|XRESOLUTION|YRESOLUTION|EXTRASAMPLES|SAMPLEFORMAT)' /mingw64/include/tiff.h
2984 // const uint16_t tcTIFFTAG_IMAGEWIDTH = 256; /* image width in pixels */
2985 // const uint16_t tcTIFFTAG_IMAGELENGTH = 257; /* image height in pixels */
2986 // const uint16_t tcTIFFTAG_BITSPERSAMPLE = 258; /* bits per channel (sample) */
2987 // const uint16_t tcTIFFTAG_COMPRESSION = 259; /* data compression technique */
2988 // const uint16_t tcTIFFTAG_PHOTOMETRIC = 262; /* photometric interpretation */
2989 // const uint16_t tcTIFFTAG_STRIPOFFSETS = 273; /* offsets to data strips */
2990 // const uint16_t tcTIFFTAG_ORIENTATION = 274; /* +image orientation */
2991 // const uint16_t tcTIFFTAG_SAMPLESPERPIXEL = 277; /* samples per pixel */
2992 // const uint16_t tcTIFFTAG_ROWSPERSTRIP = 278; /* rows per strip of data */
2993 // const uint16_t tcTIFFTAG_STRIPBYTECOUNTS = 279; /* bytes counts for strips */
2994 // const uint16_t tcTIFFTAG_XRESOLUTION = 282; /* pixels/resolution in x */
2995 // const uint16_t tcTIFFTAG_YRESOLUTION = 283; /* pixels/resolution in y */
2996 // const uint16_t tcTIFFTAG_PLANARCONFIG = 284; /* storage organization */
2997 // const uint16_t tcTIFFTAG_RESOLUTIONUNIT = 296; /* units of resolutions */
2998 // const uint16_t tcTIFFTAG_EXTRASAMPLES = 338; /* !info about extra samples */
2999 // const uint16_t tcTIFFTAG_SAMPLEFORMAT = 339; /* !data sample format */
3000
3001 endianType fe = platformEndianness(); // Endian Type
3002 uint16_t endianNum = (fe == endianType::LITTLE ? tcTIFF_LITTLEENDIAN : tcTIFF_BIGENDIAN); // Endianness Magic Number
3003 uint32_t tifWidth = (uint32_t)rcConverter.getNumPixX(); // ImageWidth
3004 uint32_t tifLength = (uint32_t)rcConverter.getNumPixY(); // ImageLength & RowsPerStrip
3005 uint32_t tifSPP = (uint32_t)rcConT::colorType::channelCount; // SamplesPerPixel
3006 uint16_t tifBPS = (uint16_t)(rcConT::colorType::bitsPerChan); // BitsPerSample
3007 uint32_t bytePerSmp = tifBPS / 8; // Bytes per sample
3008 uint32_t tifSBC = tifLength * tifWidth * bytePerSmp * tifSPP; // StripByteCounts
3009 bool haveRGB = tifSPP>=3; // TRUE if this image has RGB data (at least 3 channels)
3010 uint16_t numImgSmp = (haveRGB ? 3 : 1); // Number of samples used for image data (3 for RGB, 1 otherwise)
3011 uint16_t tifPMI = (haveRGB ? tcPHOTOMETRIC_RGB : tcPHOTOMETRIC_MINISBLACK); // PhotometricInterp
3012 uint16_t tifPC = tcPLANARCONFIG_CONTIG; // Planarconfig
3013 uint16_t tifOri = tcORIENTATION_TOPLEFT; // Orientation
3014 uint16_t tifResU = tcRESUNIT_NONE; // Resolution Unit
3015 bool haveXS = !((tifSPP==1) || (tifSPP==3)); // TRUE if this image has ExtraSamples data
3016 bool haveManyXS = tifSPP>4; // TRUE if this image has MORE THAN ONE ExtraSamples data
3017 uint16_t numTags = 1+14 + (haveXS ? 1 : 0); // Number fo tags in this image
3018 bool haveManyBPS = tifSPP>1; // TRUE if this image has MORE THAN ONE BitsPerSample data
3019 uint32_t numXS = tifSPP - numImgSmp; // Number of extra samples
3020 uint32_t xResOff = 14 + 12 * numTags; // XResolution offset
3021 uint32_t yResOff = xResOff + 8; // YResolution offset
3022 uint32_t bpsOff = yResOff + 8; // BitsPerSample offset
3023 uint32_t xsOff = bpsOff + (haveManyBPS ? 2 * tifSPP : 0); // ExtraSamples offset
3024 uint32_t imgOff = xsOff + (haveManyXS ? 2 * numXS : 0); // Image Data offset
3025 uint16_t sampFmt = (rcConT::colorType::chanIsInt ? tcSAMPLEFORMAT_UINT : tcSAMPLEFORMAT_IEEEFP); // SampleFormat (1=unsigned, 3=IEEE)
3026
3027 std::ofstream outStream;
3028 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
3029 if (outStream.is_open())
3030 outStream.imbue(std::locale::classic());
3031 else
3032 return 1;
3033
3034 writeUIntToStream(outStream, fe, 2, endianNum); // Write: little endian magic number
3035 writeUIntToStream(outStream, fe, 2, 42); // Write: TIFF magic number
3036 writeUIntToStream(outStream, fe, 4, 8); // Write: IDF offset
3037 writeUIntToStream(outStream, fe, 2, numTags); // Tag Count
3038 writeUIntToStream(outStream, fe, 2, 0x100); writeUIntToStream(outStream, fe, 2, 4);
3039 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifWidth); // ImageWidth
3040 writeUIntToStream(outStream, fe, 2, 0x101); writeUIntToStream(outStream, fe, 2, 4);
3041 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // ImageLength
3042 writeUIntToStream(outStream, fe, 2, 0x102); writeUIntToStream(outStream, fe, 2, 3);
3043 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifBPS); writeUIntToStream(outStream, fe, 2, 0); // BitsPerSample
3044 writeUIntToStream(outStream, fe, 2, 0x103); writeUIntToStream(outStream, fe, 2, 3);
3045 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, 1); writeUIntToStream(outStream, fe, 2, 0); // Compression
3046 writeUIntToStream(outStream, fe, 2, 0x106); writeUIntToStream(outStream, fe, 2, 3);
3047 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPMI); writeUIntToStream(outStream, fe, 2, 0); // PhotometricIn
3048 writeUIntToStream(outStream, fe, 2, 0x111); writeUIntToStream(outStream, fe, 2, 4);
3049 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, imgOff); // StripOffsets
3050 writeUIntToStream(outStream, fe, 2, 0x112); writeUIntToStream(outStream, fe, 2, 3);
3051 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifOri); writeUIntToStream(outStream, fe, 2, 0); // Orientation
3052 writeUIntToStream(outStream, fe, 2, 0x115); writeUIntToStream(outStream, fe, 2, 3);
3053 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifSPP); writeUIntToStream(outStream, fe, 2, 0); // SamplesPerPixel
3054 writeUIntToStream(outStream, fe, 2, 0x116); writeUIntToStream(outStream, fe, 2, 4);
3055 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // RowsPerStrip
3056 writeUIntToStream(outStream, fe, 2, 0x117); writeUIntToStream(outStream, fe, 2, 4);
3057 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifSBC); // StripByteCounts
3058 writeUIntToStream(outStream, fe, 2, 0x11A); writeUIntToStream(outStream, fe, 2, 5);
3059 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, xResOff); // XResolution
3060 writeUIntToStream(outStream, fe, 2, 0x11B); writeUIntToStream(outStream, fe, 2, 5);
3061 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, yResOff); // YResolution
3062 writeUIntToStream(outStream, fe, 2, 0x11C); writeUIntToStream(outStream, fe, 2, 3);
3063 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPC); writeUIntToStream(outStream, fe, 2, 0); // PlanarConf
3064 writeUIntToStream(outStream, fe, 2, 0x128); writeUIntToStream(outStream, fe, 2, 3);
3065 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifResU); writeUIntToStream(outStream, fe, 2, 0); // ResolutionUnit
3066 if(haveXS) { // ExtraSamples
3067 if(haveManyXS) {
3068 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3069 writeUIntToStream(outStream, fe, 4, numXS); writeUIntToStream(outStream, fe, 4, xsOff);
3070 } else {
3071 if(markAlpha) { // is chan4alpha
3072 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3073 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1);
3074 } else {
3075 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3076 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 0);
3077 }
3078 }
3079 }
3080
3081 writeUIntToStream(outStream, fe, 2, 0x153);
3082 writeUIntToStream(outStream, fe, 2, 3); writeUIntToStream(outStream, fe, 4, 1);
3083 writeUIntToStream(outStream, fe, 2, sampFmt); writeUIntToStream(outStream, fe, 2, 0); // SampleFormat
3084
3085 writeUIntToStream(outStream, fe, 4, 0); // IFD END
3086 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // XResolutionData
3087 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // YResolutionData
3088 if(haveManyBPS) { // YResolutionData
3089 for(unsigned int i=0; i<tifSPP; i++)
3090 writeUIntToStream(outStream, fe, 2, tifBPS);
3091 }
3092 if(haveManyXS) // ExtraSamplesData (can't be RGBA is on xtra, not many)
3093 for(unsigned int i=0; i<numXS; i++)
3094 writeUIntToStream(outStream, fe, 4, 0);
3095 // Image data
3096 intCrdT x, y;
3097 bool yNat = !(rcConverter.isIntAxOrientationNaturalY());
3098 bool xNat = rcConverter.isIntAxOrientationNaturalX();
3099 for((yNat?y=0:y=(rcConverter.getNumPixY()-1)); (yNat?y<rcConverter.getNumPixY():y>=0); (yNat?y++:y--)) {
3100 for((xNat?x=0:x=(rcConverter.getNumPixX()-1)); (xNat?x<rcConverter.getNumPixX():x>=0); (xNat?x++:x--)) {
3101 typename rcConT::colorType aColor = rcConverter.getPxColorNC(x, y);
3102 for(int c=0; c<aColor.channelCount; c++) {
3103 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
3104 if (rcConT::colorType::chanIsInt)
3105 writeUIntToStream(outStream, fe, bytePerSmp, aChanValue); // Sample Data
3106 else
3107 outStream.write((const char *)&aChanValue, bytePerSmp); // Sample Data
3108 }
3109 }
3110 }
3111
3112 return 0;
3113 }
3114
3115////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3116 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3117 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3118 int
3120 intCrdT x1, intCrdT y1,
3121 intCrdT x2, intCrdT y2,
3122 int redChan, int greenChan, int blueChan, int alphaChan) {
3123 if(x1 > x2) // Get x1 < x2
3124 std::swap(x1, x2);
3125 if(y1 > y2) // Get y1 < y2
3126 std::swap(y1, y2);
3127
3128 if(x1 < 0) return 1; // Outside of canvas
3129 if(x2 >= numPixX) return 1; // Outside of canvas
3130 if(y1 < 0) return 1; // Outside of canvas
3131 if(y2 >= numPixY) return 1; // Outside of canvas
3132 if(x2 < x1) return 2; // Region too small (x direction)
3133 if(y2 < y1) return 3; // Region too small (y direction)
3134
3135 int bytesPerPix = (redChan<0?0:1) + (greenChan<0?0:1) + (blueChan<0?0:1) + (alphaChan<0?0:1);
3136 if(bytesPerPix < 1) return 4; // Exit if no channels selected
3137
3138 if(rasterData == 0) // Allocate space if rasterData==NULL. Caller must delete[]
3139 rasterData = (uint8_t *) new uint8_t[(y2-y1+1)*(x2-x1+1)*bytesPerPix];
3140
3141 if(rasterData == 0) return 5; // Exit if something went wrong with allocate...
3142
3143 uint8_t *curPixComp = (uint8_t *)rasterData;
3144 for(intCrdT y=y1; y<=y2; y++) {
3145 for(intCrdT x=x1; x<=x2; x++) {
3146 colorT aColor = getPxColorNC(x, y);
3147 if(redChan >= 0) curPixComp[redChan] = aColor.getChan_byte(aColor.bestRedChan());
3148 if(greenChan >= 0) curPixComp[greenChan] = aColor.getChan_byte(aColor.bestGreenChan());
3149 if(blueChan >= 0) curPixComp[blueChan] = aColor.getChan_byte(aColor.bestBlueChan());
3150 if(alphaChan >= 0) curPixComp[alphaChan] = aColor.getChan_byte(aColor.bestAlphaChan());
3151 curPixComp += bytesPerPix;
3152 } /* end for x */
3153 } /* end for y */
3154
3155 return 0;
3156 }
3157
3158////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3159 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3160 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3161 inline intCrdT
3163 if(realAxOrientationX == realAxisOrientation::NATURAL)
3164 return static_cast<intCrdT>((static_cast<fltCrdT>(x) - minRealX) / pixWidX);
3165 else
3166 return static_cast<intCrdT>((maxRealX - static_cast<fltCrdT>(x)) / pixWidX);
3167 }
3168
3169////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3170 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3171 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3172 inline intCrdT
3174 if(realAxOrientationY == realAxisOrientation::NATURAL)
3175 return static_cast<intCrdT>((static_cast<fltCrdT>(y) - minRealY) / pixWidY);
3176 else
3177 return static_cast<intCrdT>((maxRealY - static_cast<fltCrdT>(y)) / pixWidY);
3178 }
3179
3180////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3181 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3182 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3183 inline fltCrdT
3185 if(realAxOrientationX == realAxisOrientation::NATURAL)
3186 return static_cast<fltCrdT>(x) * pixWidX + minRealX;
3187 else
3188 return maxRealX - static_cast<fltCrdT>(x) * pixWidX;
3189 }
3190
3191////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3192 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3193 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3194 inline fltCrdT
3196 if(realAxOrientationY == realAxisOrientation::NATURAL)
3197 return static_cast<fltCrdT>(y) * pixWidY + minRealY;
3198 else
3199 return maxRealY - static_cast<fltCrdT>(y) * pixWidY;
3200 }
3201
3202////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3203 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3204 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3205 colorT*
3207 colorT *pixelsCopy = new colorT[numPixX * numPixY];
3208 for(intCrdT y=0; y<numPixY; y++)
3209 for(intCrdT x=0; x<numPixX; x++)
3210 pixelsCopy[numPixX * y + x] = getPxColorNC(x, y);
3211 }
3212
3213////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3214 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3215 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3216 inline colorT
3218 if(isOnCanvas(x, y)) [[likely]]
3219 return pixels[numPixX * y + x];
3220 else
3221 return colorT().setToBlack();
3222 }
3223
3224////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3225 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3226 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3227 inline colorT
3229 switch (interpMethod) {
3230 case interpolationType::BILINEAR : return getPxColorInterpBLin(x, y);
3231 case interpolationType::TRUNCATE : return getPxColorInterpBLin(x, y);
3232 case interpolationType::NEAREST : return getPxColorInterpBLin(x, y);
3233 case interpolationType::AVERAGE4 : return getPxColorInterpBLin(x, y);
3234 case interpolationType::AVERAGE9 : return getPxColorInterpBLin(x, y);
3235 default : return colorT("green"); // Just in case I add an enum value, and forget to update this switch.
3236 }
3237 }
3238
3239////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3240 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3241 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3242 colorT
3244 double x1 = std::floor(x);
3245 double y1 = std::floor(y);
3246 double x2 = std::ceil(x);
3247 double y2 = std::ceil(y);
3248
3249 intCrdT x1i = static_cast<intCrdT>(x1);
3250 intCrdT y1i = static_cast<intCrdT>(y1);
3251 intCrdT x2i = static_cast<intCrdT>(x2);
3252 intCrdT y2i = static_cast<intCrdT>(y2);
3253
3254 colorT cF;
3255
3256 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3257 double eps = 0.00001;
3258 double xD21 = x2 - x1;
3259 double yD21 = y2 - y1;
3260 double wH = 1.0;
3261 if (xD21 > eps)
3262 wH = (x - x1) / xD21;
3263 double wV = 1.0;
3264 if (yD21 > eps)
3265 wV = (y - y1) / yD21;
3266
3267 colorT c1;
3268 colorT c2;
3269 c1.linearInterpolate(wH, getPxColorRefNC(x1i, y1i), getPxColorRefNC(x2i, y1i));
3270 c2.linearInterpolate(wH, getPxColorRefNC(x1i, y2i), getPxColorRefNC(x2i, y2i));
3271 cF.linearInterpolate(wV, c1, c2);
3272 } else {
3273 cF.setToBlack();
3274 }
3275 return cF;
3276 }
3277
3278////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3279 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3280 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3281 inline colorT
3283 return getPxColor(static_cast<intCrdT>(std::trunc(x)), static_cast<intCrdT>(std::trunc(y)));
3284 }
3285
3286////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3287 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3288 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3289 inline colorT
3291 return getPxColor(static_cast<intCrdT>(std::round(x)), static_cast<intCrdT>(std::round(y)));
3292 }
3293
3294////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3295 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3296 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3297 inline colorT
3299 intCrdT xi = static_cast<intCrdT>(std::round(x));
3300 intCrdT yi = static_cast<intCrdT>(std::round(y));
3301 colorT newColor;
3302 for(int chan=0; chan<colorT::channelCount; chan++) {
3303 colorChanArithSDPType newChanValue = 0;
3304 for(intCrdT ydi=-1; ydi<=1; ydi++) {
3305 intCrdT icY = yi + ydi;
3306 for(intCrdT xdi=-1; xdi<=1; xdi++) {
3307 intCrdT icX = xi + xdi;
3308 if (!(isCliped(icX, icY))) {
3309 newChanValue += getPxColor(icX, icY).getChan(chan);
3310 }
3311 }
3312 }
3313 newColor.setChan(chan, static_cast<colorChanType>(newChanValue / 9));
3314 }
3315 return newColor;
3316 }
3317
3318////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3319 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3320 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3321 colorT
3323 double x1 = std::floor(x);
3324 double y1 = std::floor(y);
3325 double x2 = std::ceil(x);
3326 double y2 = std::ceil(y);
3327
3328 intCrdT x1i = static_cast<intCrdT>(x1);
3329 intCrdT y1i = static_cast<intCrdT>(y1);
3330 intCrdT x2i = static_cast<intCrdT>(x2);
3331 intCrdT y2i = static_cast<intCrdT>(y2);
3332
3333 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3334
3335 colorT c1 = pixels[numPixX * y1i + x1i];
3336 c1.tfrmMean(pixels[numPixX * y1i + x2i]);
3337
3338 colorT c2 = pixels[numPixX * y2i + x1i];
3339 c2.tfrmMean(pixels[numPixX * y2i + x2i]);
3340
3341 c1.tfrmMean(c2);
3342
3343 return c1;
3344 } else {
3345 return colorT().setToBlack();
3346 }
3347 }
3348
3349// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3350// template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3351// requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3352// void
3353// ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts) {
3354// moveTo(x2, y2); // Do this first
3355// intCrdT x, y;
3356// if(y1 == y2) { // slope = 0
3357// if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
3358// return;
3359// if(x1 > x2) // . Fix point ordering
3360// std::swap(x1, x2);
3361// if(x1 < 0) // . Clip left
3362// x1 = 0;
3363// if(x2 >= numPixX) // . Clip right
3364// x2 = numPixX - 1;
3365// //drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
3366// return; // mark edge
3367// } else if(x1 == x2) { // slope = infinity
3368// if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
3369// return;
3370// if(y1 > y2) // . Fix point ordering
3371// std::swap(y1, y2);
3372// if(y1 < 0) // . Clip top
3373// y1 = 0;
3374// if(y2 >= numPixY) // . Clip bottom
3375// y2 = numPixY - 1;
3376// //drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
3377// for(y=y1; y<=y2; y++) pts[y] = x1; // mark edge
3378// } else { // Slope is not infinity or 0...
3379// int dx, dy;
3380// if(x1 > x2) { // . Fix point ordering
3381// std::swap(x1, x2);
3382// std::swap(y1, y2);
3383// }
3384// dx = x2 - x1; // . Compute the slope
3385// dy = y2 - y1;
3386// if(dx == dy) { // . Slope = 1
3387// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
3388// return;
3389// if(x1 < 0) { // .. Clip left
3390// y1 = y1 - x1;
3391// x1 = 0;
3392// }
3393// if(y1 < 0) { // .. Clip top
3394// x1 = x1 - y1;
3395// y1 = 0;
3396// }
3397// if(x2 >= numPixX) { // .. Clip right
3398// y2 = y2 - (x2 - numPixX) - 1;
3399// x2 = numPixX - 1;
3400// }
3401// if(y2 >= numPixY) { // .. Clip bottom
3402// x2 = x2 - (y2 - numPixY) - 1;
3403// y2 = numPixY - 1;
3404// }
3405// for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
3406// //drawPointNC(x, y, color);
3407// pts[y] = x; // mark edge
3408// } else if(dx == -dy) { // . Slope = -1
3409// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
3410// return;
3411// if(x1 < 0) { // .. Clip left
3412// y1 = y1 + x1;
3413// x1 = 0;
3414// }
3415// if(x2 >= numPixX) { // .. Clip right
3416// y2 = y2 + (x2 - (numPixX - 1));
3417// x2 = numPixX - 1;
3418// }
3419// if(y2 < 0) { // .. Clip top
3420// x2 = x2 + y2;
3421// y2 = 0;
3422// }
3423// if(y1 >= numPixY) { // .. Clip bottom
3424// x1 = x1 + (y1 - (numPixY - 1));
3425// y1 = numPixY - 1;
3426// }
3427// for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
3428// //drawPointNC(x, y, color);
3429// pts[y] = x; // mark edge
3430// } else { // . Slope != 1, -1, 0, \infinity
3431// int s, dx2, dy2;
3432// dx2 = 2*dx;
3433// dy2 = 2*dy;
3434// if(dy > 0) { // .. Positive Slope
3435// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
3436// return;
3437// if(x1 < 0) { // ... Clip left
3438// y1 = (int)(1.0*y1-x1*dy/dx);
3439// x1 = 0;
3440// }
3441// if(y1 < 0) { // ... Clip top
3442// x1 = (int)(1.0*x1-y1*dx/dy);
3443// y1 = 0;
3444// }
3445// if(x2 >= numPixX) { // ... Clip right
3446// y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
3447// x2 = numPixX - 1;
3448// }
3449// if(y2 >= numPixY) { // ... Clip bottom
3450// x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
3451// y2 = numPixY - 1;
3452// }
3453// if(dx > dy) { // ... 0 < Slope < 1
3454// s = dy2 - dx;
3455// x=x1;
3456// y=y1;
3457// while(x<=x2) { // .... Draw Line
3458// //drawPoint(x, y, color);
3459// pts[y] = x; // mark edge
3460// if(s < 0) {
3461// s += dy2;
3462// } else {
3463// y++;
3464// s += dy2 - dx2;
3465// }
3466// x++;
3467// }
3468// } else { // ... 1 < Slope < infinity
3469// s = dy - dx2;
3470// x=x1;
3471// y=y1;
3472// while(y<=y2) { // .... Draw Line
3473// //drawPoint(x, y, color);
3474// pts[y] = x; // mark edge
3475// if(s > 0) {
3476// s -= dx2;
3477// } else {
3478// x++;
3479// s += dy2 - dx2;
3480// }
3481// y++;
3482// }
3483// }
3484// } else { // .. Negative Slope
3485// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
3486// return;
3487// if(x1 < 0) { // ... Clip left
3488// y1 = (int)(1.0*y1-x1*dy/dx);
3489// x1 = 0;
3490// }
3491// if(y2 < 0) { // ... Clip top
3492// x2 = (int)(1.0*x2-y2*dx/dy);
3493// y2 = 0;
3494// }
3495// if(x2 >= numPixX) { // ... Clip right
3496// y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
3497// x2 = numPixX - 1;
3498// }
3499// if(y1 >= numPixY) { // ... Clip bottom
3500// x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
3501// y1 = numPixY - 1;
3502// }
3503// if(dx > -dy) { // ... 0 > Slope > -infinity
3504// s = dy2 + dx;
3505// x=x1;
3506// y=y1;
3507// while(x<=x2) { // .... Draw Line
3508// //drawPoint(x, y, color);
3509// pts[y] = x; // mark edge
3510// if(s > 0) {
3511// s += dy2;
3512// } else {
3513// y--;
3514// s += dy2 + dx2;
3515// }
3516// x++;
3517// }
3518// } else { // ... -1 > Slope > -inf
3519// s = dy + dx2;
3520// x=x1;
3521// y=y1;
3522// while(y>=y2) { // .... Draw Line
3523// //drawPoint(x, y, color);
3524// pts[y] = x; // mark edge
3525// if(s < 0) {
3526// s += dx2;
3527// } else {
3528// x++;
3529// s += dy2 + dx2;
3530// }
3531// y--;
3532// }
3533// }
3534// }
3535// }
3536// }
3537// }
3538
3539////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3540 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3541 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3542 inline void
3543 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin) {
3544 // This code is essentially the line drawing code with some simplifications.
3545 intCrdT x, y;
3546 if(x1 == x2) { // slope = infinity
3547 if(y1 > y2) // Fix point ordering
3548 std::swap(y1, y2);
3549 for(y=y1; y<=y2; y++) // Draw PIxels: drawVertLineNC(y1, y2, x1, color);
3550 pts[y]=x1; // set bound
3551 } else { // Slope is not infinity or 0...
3552 int dx, dy;
3553 if(x1 > x2) { // Fix point ordering
3554 std::swap(x1, x2);
3555 std::swap(y1, y2);
3556 }
3557 dx = x2 - x1; // Compute the slope
3558 dy = y2 - y1;
3559 if(dx == dy) { // Slope = 1
3560 for(x=x1,y=y1;x<=x2;y++,x++) // Draw Pixels
3561 pts[y]=x; // set bound
3562 } else if(dx == -dy) { // Slope = -1
3563 for(x=x1,y=y1;x<=x2;y--,x++) // Draw Pixels
3564 pts[y]=x; // set bound
3565 } else { // Slope != 1, -1, 0, \infinity
3566 int s, dx2, dy2;
3567 dx2 = 2*dx;
3568 dy2 = 2*dy;
3569 if(dy > 0) { // Positive Slope
3570 if(dx > dy) { // 0 < Slope < 1
3571 if (findMin) {
3572 s = dy2 - dx;
3573 x=x1;
3574 y=y1;
3575 intCrdT lastY=y-1;
3576 while(x<=x2) { // Draw Line
3577 if (y != lastY)
3578 pts[y]=x; // set bound
3579 lastY = y;
3580 if(s < 0) {
3581 s += dy2;
3582 } else {
3583 y++;
3584 s += dy2 - dx2;
3585 }
3586 x++;
3587 }
3588 } else { // works.
3589 s = dy2 - dx;
3590 x=x1;
3591 y=y1;
3592 while(x<=x2) { // Draw Line
3593 pts[y]=x; // set bound
3594 if(s < 0) {
3595 s += dy2;
3596 } else {
3597 y++;
3598 s += dy2 - dx2;
3599 }
3600 x++;
3601 }
3602 }
3603 } else { // 1 < Slope < infinity
3604 s = dy - dx2;
3605 x=x1;
3606 y=y1;
3607 while(y<=y2) { // Draw Line
3608 pts[y]=x; // set bound
3609 if(s > 0) {
3610 s -= dx2;
3611 } else {
3612 x++;
3613 s += dy2 - dx2;
3614 }
3615 y++;
3616 }
3617 }
3618 } else { // Negative Slope
3619 if(dx > -dy) { // 0 > Slope > -1
3620 if (findMin) {
3621 s = dy2 + dx;
3622 x=x1;
3623 y=y1;
3624 intCrdT lastY=y-1;
3625 while(x<=x2) { // Draw Line
3626 if (y != lastY)
3627 pts[y]=x; // set bound
3628 lastY = y;
3629 if(s > 0) {
3630 s += dy2;
3631 } else {
3632 y--;
3633 s += dy2 + dx2;
3634 }
3635 x++;
3636 }
3637 } else {
3638 s = dy2 + dx;
3639 x=x1;
3640 y=y1;
3641 while(x<=x2) { // Draw Line
3642 pts[y]=x; // set bound
3643 if(s > 0) {
3644 s += dy2;
3645 } else {
3646 y--;
3647 s += dy2 + dx2;
3648 }
3649 x++;
3650 }
3651 }
3652 } else { // -1 > Slope > -inf
3653 s = dy + dx2;
3654 x=x1;
3655 y=y1;
3656 while(y>=y2) { // Draw Line
3657 pts[y]=x; // set bound
3658 if(s < 0) {
3659 s += dx2;
3660 } else {
3661 x++;
3662 s += dy2 + dx2;
3663 }
3664 y--;
3665 }
3666 }
3667 }
3668 }
3669 }
3670 }
3671
3672////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3673 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3674 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3675 inline void
3676 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3677 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color, color, color, true);
3678 }
3679
3680////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3681 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3682 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3683 inline void
3685 intCrdT x2, intCrdT y2,
3686 intCrdT x3, intCrdT y3,
3687 colorArgType color1, colorArgType color2, colorArgType color3) {
3688 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color1, color2, color3, false);
3689 }
3690
3691////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3692 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3693 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3694 void
3696 intCrdT x2, intCrdT y2,
3697 intCrdT x3, intCrdT y3,
3698 colorT c1, colorT c2, colorT c3, bool solid) { // Not colorArgType because of std::swap
3699 static intCrdT *minPts, *maxPts;
3700 static intCrdT numPts;
3701
3702 if( isCliped(x1, y1) || isCliped(x2, y2) || isCliped(x3, y3))
3703 return;
3704
3705 ///////////////////////////////////////////////////////////////////////////////////
3706 // Check our work space, and allocate/reallocate as required.
3707 if(minPts == NULL) { // First time in function -- allocate
3708 minPts = new intCrdT[numPixY];
3709 maxPts = new intCrdT[numPixY];
3710 numPts = numPixY;
3711 } else { // Not our first time! We have a work space.
3712 if(numPts != numPixY) { // Work space is wrong size -- reallocate
3713 delete[] minPts;
3714 delete[] maxPts;
3715 minPts = new intCrdT[numPixY];
3716 maxPts = new intCrdT[numPixY];
3717 numPts = numPixY;
3718 }
3719 }
3720
3721 ///////////////////////////////////////////////////////////////////////////////////
3722 if (!(solid) && ((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) == 0))
3723 return;
3724
3725 ///////////////////////////////////////////////////////////////////////////////////
3726 // Sort (x1,y1), (x2,y2), (x3,y3) so that y1 >= y2, y3 and y3 <= y2, y1
3727 if(y1 > y2) { // top != 2 && bot != 1
3728 if(y1 > y3) { // top != 3 y1>y2 y1>y3 y2>y3 top bot
3729 if(y2 > y3) { // bot != 2 . . . . .
3730 // T T T 1 3 NOP
3731 } else { // bot != 3 . . . . .
3732 std::swap(y2,y3); // T T F 1 2 SWAP(2,3)
3733 std::swap(x2,x3); // . . . . .
3734 std::swap(c2,c3); // . . . . .
3735 } // . . . . .
3736 } else { // top != 1 . . . . .
3737 std::swap(y1,y3); // T F U 3 2 SWAP(1,3) SWAP(2,3)
3738 std::swap(y2,y3); // . . . . .
3739 std::swap(x1,x3); // . . . . .
3740 std::swap(x2,x3); // . . . . .
3741 if(!solid) { // . . . . .
3742 std::swap(c1,c3); // . . . . .
3743 std::swap(c2,c3); // . . . . .
3744 } // . . . . .
3745 } // . . . . .
3746 } else { // top != 1 . . . . .
3747 if(y2 > y3) { // top != 3 && bot != 2 . . . . .
3748 if(y1 > y3) { // bot != 1 . . . . .
3749 std::swap(y1,y2); // F T T 2 3 SWAP(1,2)
3750 std::swap(x1,x2); // . . . . .
3751 std::swap(c1,c2); // . . . . .
3752 } else { // bot != 3 . . . . .
3753 std::swap(y1,y2); // F F T 2 1 SWAP(1,2) SWAP(2,3)
3754 std::swap(y2,y3); // . . . . .
3755 std::swap(x1,x2); // . . . . .
3756 std::swap(x2,x3); // . . . . .
3757 if(!solid) { // . . . . .
3758 std::swap(c1,c2); // . . . . .
3759 std::swap(c2,c3); // . . . . .
3760 } // . . . . .
3761 } // . . . . .
3762 } else { // top != 2 && bot != 3 . . . . .
3763 std::swap(y1,y3); // F U F 3 1 SWAP(1,3)
3764 std::swap(x1,x3); // . . . . .
3765 std::swap(c1,c3); // . . . . .
3766 }
3767 }
3768
3769 ///////////////////////////////////////////////////////////////////////////////////////
3770 /* cA y1==y2 point 1,2,3 */
3771 /* cB-cG y1==y2 h line 1,2---3 3---1,2 1,3---2 2---1,3 2,3---1 1---2,3 */
3772 /* cH-cJ y1==y2 v line 1,2 1,2 1,2 */
3773 /* \ | / */
3774 /* 3 3 3 */
3775 /* cK-cL y1==y2 tri 1---2 2---1 */
3776 /* \ / \ / */
3777 /* 3 3 */
3778 /* cM-cO y2=y3 v line 1 1 1 */
3779 /* \ | / */
3780 /* 2,3 2,3 2,3 */
3781 /* cP-cQ y2=y3 tri 1 1 */
3782 /* / \ / \ */
3783 /* 2---3 3---2 */
3784 /* cR-cS General 1 1 Note x1 need not equal x3 in these cases! */
3785 /* |\ /| It is just difficult to draw a case with */
3786 /* | 2 2 | x1 != x3 with tiny ASCII art... */
3787 /* |/ \| */
3788 /* 3 3 */
3789 ///////////////////////////////////////////////////////////////////////////////////////
3790
3791 if(y1==y3) { // cA-cG
3792 minPts[y1] = mjr::math::odr::min3(x1, x2, x3); //
3793 maxPts[y1] = mjr::math::odr::max3(x1, x2, x3); //
3794 } else { // cH-cS
3795 if(y1==y2) { // cH-cL
3796 if(x1==x2) { // cH-cJ
3797 triangleEdger(x1, y1, x3, y3, minPts, true); //
3798 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3799 } else if(x1<x2) { // cK
3800 triangleEdger(x1, y1, x3, y3, minPts, true); //
3801 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3802 } else { // cJ
3803 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3804 triangleEdger(x2, y2, x3, y3, minPts, true); //
3805 } //
3806 } else if(y2==y3) { // cM-cQ
3807 if(x2==x3) { // cM-cO
3808 triangleEdger(x1, y1, x3, y3, minPts, true); //
3809 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3810 } else if(x2<x3) { // cP
3811 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3812 triangleEdger(x2, y2, x1, y1, minPts, true); //
3813 } else { // cQ
3814 triangleEdger(x1, y1, x3, y3, minPts, true); //
3815 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3816 } //
3817 } else { // cR-cS
3818 double xOt = (x1*y3+x3*y2-x1*y2-x3*y1); //
3819 double xOb = (y3-y1); //
3820 if(xOt/xOb < x2) { // cR
3821 triangleEdger(x1, y1, x3, y3, minPts, true); //
3822 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3823 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3824 } else { // cS
3825 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3826 triangleEdger(x2, y2, x1, y1, minPts, true); //
3827 triangleEdger(x2, y2, x3, y3, minPts, true); //
3828 } //
3829 } //
3830 } //
3831
3832 ///////////////////////////////////////////////////////////////////////////////////
3833 // Fill between the left and right bits.
3834 if(solid) {
3835 for(intCrdT y=y3; y<=y1; y++)
3836 drawLine(minPts[y], y, maxPts[y], y, c1);
3837 } else {
3838 for(intCrdT y=y3; y<=y1; y++)
3839 for(intCrdT x=minPts[y]; x<=maxPts[y]; x++) {
3840 /* Performance & Correctness: This code seems very poorly optimized. Especially the computation of w3 instead of simply using 1-w1-w2, and the
3841 division by the sum w1+w2+s3 instead of by the total triangle area. We are working with integer coordinates, and thus we have some fluff in the
3842 computations. Sometimes, for example, the coordinates of a fill point won't, technically, be in the triangle. Or the sum of the areas
3843 sub-triangles might not equal the total area. So we compute w3 and divide by the sum so that we *always* get consistent results and coloring on
3844 the edges of triangles regardless of the order of the given points. Yea, it slows things down, but my use cases for filled triangles demand
3845 consistency and accuracy on edges. The repeated common expressions are optimized by the compiler. This branch is roughly 15x slower than the
3846 solid branch above. */
3847 colorChanArithFltType w1 = std::abs(static_cast<colorChanArithFltType>( x*(y2 - y3) + x2*(y3 - y) + x3*(y - y2)));
3848 colorChanArithFltType w2 = std::abs(static_cast<colorChanArithFltType>(x1*(y - y3) + x*(y3 - y1) + x3*(y1 - y)));
3849 colorChanArithFltType w3 = std::abs(static_cast<colorChanArithFltType>(x1*(y2 - y) + x2*(y - y1) + x*(y1 - y2)));
3850 drawPointNC(x, y, colorT().wMean(w1/(w1+w2+w3), w2/(w1+w2+w3), w3/(w1+w2+w3), c1, c2, c3));
3851 }
3852 }
3853 }
3854
3855////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3856 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3857 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3858 inline void
3860 drawPLCurve(numPoints, x, y, dfltColor);
3861 }
3862
3863////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3864 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3865 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3866 inline void
3868 for(int i=0; i<numPoints-1; i++)
3869 drawLine(real2intX(x[i]), real2intY(y[i]), real2intX(x[i+1]), real2intY(y[i+1]), color);
3870 }
3871
3872////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3873 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3874 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3875 inline void
3877 drawPLCurve(numPoints, x, y, dfltColor);
3878 }
3879
3880////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3881 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3882 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3883 inline void
3885 for(int i=0; i<numPoints-1; i++)
3886 drawLine(x[i], y[i], x[i+1], y[i+1], color);
3887 }
3888
3889////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3890 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3891 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3892 inline void
3894 for(int i=0; i<numPoints-1; i++)
3895 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3896 }
3897
3898////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3899 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3900 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3901 inline void
3903 for(int i=0; i<numPoints-1; i++)
3904 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3905 }
3906
3907////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3908 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3909 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3910 inline void
3912 drawPLCurve(numPoints, thePoints, dfltColor);
3913 }
3914
3915////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3916 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3917 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3918 inline void
3920 drawPLCurve(numPoints, thePoints, dfltColor);
3921 }
3922
3923////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3924 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3925 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3926 inline void
3927 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3928 drawLine(x1, y1, x2, y2, color);
3929 drawLine(x2, y2, x3, y3, color);
3930 drawLine(x3, y3, x1, y1, color);
3931 }
3932
3933////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3934 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3935 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3936 void
3937 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
3938 int x = 0;
3939 int y = radiusX;
3940 int d = 1 - radiusX;
3941 int deltaE = 3;
3942 int deltaSE = -2 * radiusX + 5;
3943
3944 drawPoint( x+centerX, y+centerY, color);
3945 drawPoint( x+centerX,-y+centerY, color);
3946 drawPoint(-x+centerX, y+centerY, color);
3947 drawPoint(-x+centerX,-y+centerY, color);
3948 drawPoint( y+centerX, x+centerY, color);
3949 drawPoint( y+centerX,-x+centerY, color);
3950 drawPoint(-y+centerX, x+centerY, color);
3951 drawPoint(-y+centerX,-x+centerY, color);
3952
3953 while(y>x) {
3954 if(d<0) {
3955 d += deltaE;
3956 deltaE += 2;
3957 deltaSE += 2;
3958 } else {
3959 d += deltaSE;
3960 deltaE += 2;
3961 deltaSE += 4;
3962 y--;
3963 }
3964 x++;
3965 drawPoint( x+centerX, y+centerY, color);
3966 drawPoint( x+centerX,-y+centerY, color);
3967 drawPoint(-x+centerX, y+centerY, color);
3968 drawPoint(-x+centerX,-y+centerY, color);
3969 drawPoint( y+centerX, x+centerY, color);
3970 drawPoint( y+centerX,-x+centerY, color);
3971 drawPoint(-y+centerX, x+centerY, color);
3972 drawPoint(-y+centerX,-x+centerY, color);
3973 }
3974
3975 }
3976
3977////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3978 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3979 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3980 void
3981 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
3982 int minXY;
3983 int x = 0;
3984 int y = radiusX;
3985 int d = 1 - radiusX;
3986 int deltaE = 3;
3987 int deltaSE = -2 * radiusX + 5;
3988
3989 if(x > y)
3990 minXY = y;
3991 else
3992 minXY = x;
3993 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
3994 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
3995 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
3996 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
3997 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
3998 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
3999 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4000 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4001
4002 while(y>x) {
4003 if(d<0) {
4004 d += deltaE;
4005 deltaE += 2;
4006 deltaSE += 2;
4007 } else {
4008 d += deltaSE;
4009 deltaE += 2;
4010 deltaSE += 4;
4011 y--;
4012 }
4013 x++;
4014
4015 if(x > y)
4016 minXY = y;
4017 else
4018 minXY = x;
4019 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
4020 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
4021 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
4022 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
4023 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
4024 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
4025 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4026 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4027 }
4028 }
4029
4030////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4031 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4032 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4033 void
4034 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
4035 if(x1 > x2) // Get x1 < x2
4036 std::swap(x1, x2);
4037 if(y1 > y2) // Get y1 < y2
4038 std::swap(y1, y2);
4039 if( (y1 < numPixY) && (x1 < numPixX) && (y2 >= 0) && (x2 >= 0) ) { // Part of rect visible
4040 int noTop, noBottom, noLeft, noRight;
4041 if((noTop=(y1 < 0)))
4042 y1 = 0;
4043 if((noLeft=(x1 < 0)))
4044 x1 = 0;
4045 if((noBottom=(y2 >= numPixY)))
4046 y2 = numPixY - 1;
4047 if((noRight=(x2 >= numPixX)))
4048 x2 = numPixX - 1;
4049 // Draw top/bottom/left/right lines
4050 if(!noLeft) // Have left
4051 drawVertLineNC(y1, y2, x1, color);
4052 if(!noRight) // Have Right
4053 drawVertLineNC(y1, y2, x2, color);
4054 if(!noTop) // Have top
4055 drawHorzLineNC(x1, x2, y1, color);
4056 if(!noBottom) // Have bottom
4057 drawHorzLineNC(x1, x2, y2, color);
4058 }
4059 }
4060
4061////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4062 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4063 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4064 inline void
4066 if(x1 > x2) // Get x1 < x2
4067 std::swap(x1, x2);
4068 if(y1 > y2) // Get y1 < y2
4069 std::swap(y1, y2);
4070 // Clip
4071 if( (y1 >= numPixY) || (x1 >= numPixX) || (y2 < 0) || (x2 < 0) )
4072 return;
4073 if(y1 < 0)
4074 y1 = 0;
4075 if(x1 < 0)
4076 x1 = 0;
4077 if(y2 >= numPixY)
4078 y2 = numPixY - 1;
4079 if(x2 >= numPixX)
4080 x2 = numPixX - 1;
4081 for(intCrdT y=y1;y<=y2;y++)
4082 drawHorzLineNC(x1, x2, y, color);
4083 }
4084
4085////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4086 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4087 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4088 inline void
4090 /* Performance: We are depending on the compiler to eliminate this if statement because enableDrawModes is a compile time constant. */
4091 if (enableDrawModes)
4092 switch(drawMode) {
4093 case drawModeType::SET: getPxColorRefNC(x, y).copy(color); break;
4094 case drawModeType::XOR: getPxColorRefNC(x, y).tfrmXor(color); break;
4095 case drawModeType::ADDCLAMP: getPxColorRefNC(x, y).tfrmAddClamp(color); break;
4096 case drawModeType::AND: getPxColorRefNC(x, y).tfrmAnd(color); break;
4097 case drawModeType::OR: getPxColorRefNC(x, y).tfrmOr(color); break;
4098 case drawModeType::DIFFCLAMP: getPxColorRefNC(x, y).tfrmDiffClamp(color); break;
4099 case drawModeType::MULTCLAMP: getPxColorRefNC(x, y).tfrmMultClamp(color); break;
4100 }
4101 else
4102 getPxColorRefNC(x, y).copy(color);
4103 }
4104
4105////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4106 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4107 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4108 void
4110 intCrdT new_numPixX_p = xfactor*numPixX;
4111 intCrdT new_numPixY_p = xfactor*numPixY;
4112 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4113 for(intCrdT y=0, y1=0; y<numPixY; y++) {
4114 for(intCrdT x=0, x1=0; x<numPixX; x++) {
4115 for(int i=0; i<xfactor; i++) {
4116 for(int j=0; j<xfactor; j++) {
4117 new_pixels[new_numPixX_p * y1 + x1] = getPxColor(x, y);
4118 x1++;
4119 }
4120 x1-=xfactor;
4121 y1++;
4122 }
4123 x1+=xfactor;
4124 y1-=xfactor;
4125 }
4126 y1+=xfactor;
4127 }
4128 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4129 }
4130
4131////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4132 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4133 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4134 void
4136 intCrdT new_numPixX_p = numPixX/xfactor;
4137 intCrdT new_numPixY_p = numPixY/xfactor;
4138 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4139 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4140 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor)
4141 new_pixels[new_numPixX_p * y + x] = getPxColor(x1, y1);
4142
4143 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4144 }
4145
4146////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4147 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4148 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4149 void
4151 intCrdT new_numPixX_p = numPixX/xfactor;
4152 intCrdT new_numPixY_p = numPixY/xfactor;
4153 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4154 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4155 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4156 std::vector<colorChanArithSDPType> sums(colorT::channelCount, static_cast<colorChanArithSDPType>(0));
4157 for(int j=0; j<xfactor; j++)
4158 for(int i=0; i<xfactor; i++)
4159 for(int c=0; c<colorT::channelCount; c++)
4160 sums[c] += getPxColor(x1+i, y1+j).getChan(c);
4161 colorT aColor;
4162 for(int c=0; c<colorT::channelCount; c++)
4163 aColor.setChan(c, static_cast<colorChanType>(sums[c] / (xfactor*xfactor)));
4164 new_pixels[new_numPixX_p * y + x] = aColor;
4165 }
4166
4167 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4168 }
4169
4170////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4171 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4172 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4173 void
4175 intCrdT new_numPixX_p = numPixX/xfactor;
4176 intCrdT new_numPixY_p = numPixY/xfactor;
4177 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4178
4179 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4180 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4181 colorT maxColor = getPxColor(xfactor*x, xfactor*y);
4182 for(int yi=0; yi<xfactor; yi++)
4183 for(int xi=0; xi<xfactor; xi++)
4184 maxColor.tfrmMaxI(getPxColor(xfactor*x+xi, xfactor*y+yi));
4185 new_pixels[new_numPixX_p * y + x] = maxColor;
4186 }
4187
4188 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4189 }
4190
4191////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4192 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4193 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4194 void
4196 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4197 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4198 kernel[kSize * yi + xi] = exp(-(xis*xis+yis*yis)/(2*sd*sd))/(sd*sd*6.283185307179586477);
4199 double divisor = 0;
4200 for(int i=0; i<(kSize*kSize); i++)
4201 divisor += kernel[i];
4202 for(int i=0; i<(kSize*kSize); i++)
4203 kernel[i] /= divisor;
4204 }
4205
4206////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4207 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4208 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4209 void
4211 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4212 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4213 kernel[kSize * yi + xi] = 1.0/(kSize*kSize);
4214 }
4215
4216////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4217 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4218 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4219 void
4220 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::convolution(double *kernel, int kWide, int kTall, double divisor) {
4221 colorT *new_pixels = new colorT[numPixX * numPixY];
4222 // Divisor is invalid, so we compute one to use
4223 if(std::abs(divisor) < 0.0001) {
4224 divisor = 0.0;
4225 for(int i=0; i<(kWide*kTall); i++)
4226 divisor += kernel[i];
4227 }
4228 // Apply filter
4229 double tmp[colorT::channelCount];
4230 for(intCrdT y=0; y<numPixY; y++) {
4231 for(intCrdT x=0; x<numPixX; x++) {
4232 colorT newColor;
4233 for(int chan=0; chan<colorT::channelCount; chan++)
4234 tmp[chan] = 0.0;
4235 for(int yi=0, yis=-(kTall/2); yi<kTall; yi++, yis++) {
4236 intCrdT icY = y + yis;
4237 for(int xi=0,xis=-(kWide/2); xi<kWide; xi++, xis++) {
4238 intCrdT icX = x + xis;
4239 if (!(isCliped(icX, icY))) {
4240 for(int chan=0; chan<colorT::channelCount; chan++)
4241 tmp[chan] += static_cast<double>(getPxColor(icX, icY).getChan(chan)) * kernel[kWide * yi + xi];
4242 }
4243 }
4244 }
4245 for(int chan=0; chan<colorT::channelCount; chan++)
4246 new_pixels[numPixX * y + x].setChan(chan, static_cast<colorChanType>(tmp[chan] / divisor));
4247 }
4248 }
4249 rePointPixels(new_pixels, numPixX, numPixY);
4250 }
4251
4252////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4253 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4254 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4255 inline void
4257 convolution(kernel, kSize, kSize, divisor);
4258 }
4259////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4260 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4261 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4262 inline void
4264 convolution(kernel, kSize, kSize, 1.0);
4265 }
4266
4267////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4268 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4269 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4270 void
4271 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor) {
4272 intCrdT x1, y1;
4273 int actionIsMoveTo;
4274
4275 if( (glyphNum < 0) || (glyphNum > 3934) )
4276 glyphNum = 699;
4277
4278 actionIsMoveTo=1;
4279 for(int i=0; i<(mjr::hershey::chars[glyphNum]).numComp; i++) {
4280 if((mjr::hershey::chars[glyphNum]).components[2*i] == ' ') {
4281 actionIsMoveTo = 1;
4282 } else {
4283 if(isIntAxOrientationNaturalX())
4284 x1 = static_cast<intCrdT>(magX * ((mjr::hershey::chars[glyphNum]).components[2*i] - 'R'));
4285 else
4286 x1 = static_cast<intCrdT>(magX * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i]));
4287
4288 if(isIntAxOrientationNaturalY())
4289 y1 = static_cast<intCrdT>(magY * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i+1]));
4290 else
4291 y1 = static_cast<intCrdT>(magY * ((mjr::hershey::chars[glyphNum]).components[2*i+1] - 'R'));
4292
4293 if(actionIsMoveTo) {
4294 moveTo(x1+x, y1+y);
4295 actionIsMoveTo = 0;
4296 } else {
4297 drawLine(x1+x, y1+y, aColor);
4298 }
4299 }
4300 }
4301 }
4302
4303////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4304 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4305 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4306 inline void
4307 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc) {
4308 for(auto &c : aString) {
4309 int glyphNum = 0;
4310 if((c>=32) && (c<=126))
4311 glyphNum = mjr::hershey::ascii2hershey[(int)aFont][c-32];
4312 drawHersheyGlyph(glyphNum, x, y, cex, cex, aColor);
4313 x+=static_cast<intCrdT>(spc*cex);
4314 }
4315 }
4316
4317////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4318 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4319 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4320 inline void
4322 mjr::hershey::font aFont,
4323 intCrdT x, intCrdT y,
4324 colorArgType stringColor, colorArgType boxColor,
4325 double cex, intCrdT spc) {
4326 drawFillRectangle(static_cast<intCrdT>(x-spc*cex),
4327 static_cast<intCrdT>(y-spc*cex),
4328 static_cast<intCrdT>(x+spc*cex*static_cast<int>(aString.length())),
4329 static_cast<intCrdT>(y+spc*cex),
4330 boxColor);
4331 drawString(aString, aFont, x, y, stringColor, cex, spc);
4332 }
4333
4334////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4335 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4336 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4337 int
4339 char strBuf[256];
4340
4341 std::ifstream iStream(fileName, std::ios_base::binary);
4342
4343 if (!(iStream.good()))
4344 return 1;
4345
4346 iStream.getline(strBuf, 10, '\n');
4347 if (!(iStream.good()))
4348 return 11;
4349 if (iStream.gcount() != 7)
4350 return 24;
4351 if(std::string(strBuf) != std::string("MJRRAW"))
4352 return 24;
4353
4354 int fileWide = -1;
4355 int fileTall = -1;
4356 int fileChans = -1;
4357 int fileBitPerChan = -1;
4358 bool fileIsSGN = true, fileHasS = false;
4359 bool fileIsInt = true, fileHasT = false;
4360 bool fileIsLTL = true, fileHasI = false;
4361
4362 iStream.getline(strBuf, 100, '\n');
4363 if (!(iStream.good()))
4364 return 11;
4365 if (iStream.gcount() != 93)
4366 return 26;
4367
4368 std::string::size_type tagIdx;
4369 std::string::size_type prcIdx = 0;
4370 std::string strBufS(strBuf);
4371 std::string delChrs("abcdefghijklmnopqrstuvwxyz");
4372 int stoiErrorCount = 0;
4373
4374 while(true) {
4375 tagIdx = strBufS.find_first_of(delChrs, prcIdx);
4376 if (tagIdx == std::string::npos)
4377 break;
4378 // std::cout << "suc: " << strBufS.substr(prcIdx) << std::endl;
4379 // std::cout << "tok: " << strBufS.substr(prcIdx, tagIdx-prcIdx) << std::endl;
4380 try {
4381 switch(strBufS[tagIdx]) {
4382 case 'x' : fileWide = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4383 case 'y' : fileTall = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4384 case 'c' : fileChans = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4385 case 'b' : fileBitPerChan = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4386 case 's' : fileIsSGN = (strBufS[prcIdx] == 'S'); fileHasS = true; break;
4387 case 't' : fileIsInt = (strBufS[prcIdx] == 'I'); fileHasT = true; break;
4388 case 'i' : fileIsLTL = (strBufS[prcIdx] == 'L'); fileHasI = true; break;
4389 }
4390 } catch (...) {
4391 stoiErrorCount++;
4392 }
4393 prcIdx=tagIdx+1;
4394 }
4395
4396 int fileBytePerChan = fileBitPerChan / 8;
4397
4398 // std::cout << "fileWide " << fileWide << std::endl;
4399 // std::cout << "fileTall " << fileTall << std::endl;
4400 // std::cout << "fileChans " << fileChans << std::endl;
4401 // std::cout << "fileBitPerChan " << fileBitPerChan << std::endl;
4402 // std::cout << "fileIsSGN " << fileIsSGN << std::endl;
4403 // std::cout << "fileIsInt " << fileIsInt << std::endl;
4404 // std::cout << "fileIsLTL " << fileIsLTL << std::endl;
4405 // std::cout << "fileBytePerChan: " << fileBytePerChan << std::endl;
4406
4407 if (stoiErrorCount > 0)
4408 return 29;
4409
4410 if (fileWide < 0)
4411 return 33;
4412 if (fileTall < 0)
4413 return 34;
4414 if (fileChans < 0)
4415 return 35;
4416 if (fileBitPerChan < 0)
4417 return 36;
4418
4419 if (fileWide == 0)
4420 return 8;
4421 if (fileTall == 0)
4422 return 9;
4423
4424 if (fileWide > intCrdMax)
4425 return 27;
4426 if (fileTall > intCrdMax)
4427 return 28;
4428
4429 resizeCanvas(fileWide, fileTall);
4430
4431 if (fileWide != numPixX)
4432 return(12);
4433 if (fileTall != numPixY)
4434 return(14);
4435
4436 if (!(fileHasT))
4437 fileIsInt = true;
4438
4439 if (!(fileHasS))
4440 fileIsSGN = ( !(fileIsInt)); // If file is missing 's', then assume it's compatable with 't'
4441
4442 if ((colorT::chanIsInt && fileIsSGN))
4443 return 23;
4444
4445 if ((colorT::chanIsInt && !fileIsInt) ||
4446 (colorT::chanIsFloat && fileIsInt))
4447 return 21;
4448
4449 if(fileChans != colorT::channelCount)
4450 return 19;
4451
4452 if(fileBitPerChan != colorT::bitsPerChan)
4453 return 20;
4454
4455 if (!(fileHasI))
4456 fileIsLTL = (platformEndianness() == endianType::LITTLE); // missing 'i', then assume LITTLE.
4457
4458 bool reverseBits = (( fileIsLTL && (platformEndianness() == endianType::BIG)) ||
4459 (!(fileIsLTL) && (platformEndianness() == endianType::LITTLE)));
4460
4461 intCrdT x, y;
4462 bool yNat = !(isIntAxOrientationNaturalY());
4463 bool xNat = isIntAxOrientationNaturalX();
4464 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
4465 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
4466 for(int ci=0; ci<fileChans; ci++) {
4467 /* performance: An if inside a triple nexted for loop! Ouch. But chanIsInt is a compile time constant, so this should be reduced to just the
4468 branch of the if that is true. Same wit the if statement inside the else clause of this if.*/
4469 if (colorT::chanIsInt) {
4470 colorChanArithLogType shft = (reverseBits ? colorT::bitsPerChan-8 : 0);
4471 /* Note that colorChanArithLogType is always an unsigned integer type, and thus we avoid compiler errors when trying to use | on a float.
4472 When chanIsInt, colorChanArithLogType is the same as colorChanType when chanIsInt -- so a NOOP because this part of the if only gets
4473 run when chanIsInt. */
4474 colorChanArithLogType pv = 0;
4475 for(int bi=0; bi<fileBytePerChan; bi++) {
4476 colorChanArithLogType uch = (unsigned char)iStream.get();
4477 if (!(iStream.good()))
4478 return 25;
4479 if (iStream.gcount() != 1)
4480 return 25;
4481 pv = pv | static_cast<colorChanArithLogType>(uch << shft);
4482
4483 if (reverseBits)
4484 shft -= 8;
4485 else
4486 shft += 8;
4487
4488 }
4489 getPxColorRefNC(x, y).setChan(ci, static_cast<colorChanType>(pv));
4490 } else {
4491 iStream.read(strBuf, fileBytePerChan);
4492 getPxColorRefNC(x, y).setChan(ci, *((colorChanType*)strBuf));
4493 }
4494 }
4495 }
4496 }
4497 iStream.close();
4498 return 0;
4499 }
4500
4501////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4502 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4503 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4504 int
4506#ifndef MRASTER_FOUND_TIFF
4507 std::cerr << "ERROR: libTIFF no supported: readTIFFfile can't read " << fileName << std::endl;
4508 return 32;
4509#else
4510 TIFF* tif;
4511 uint32_t wTIFF, hTIFF;
4512 uint16_t pmTIFF, pcTIFF, sppTIFF, bpsTIFF, fmtTIFF;
4513
4514 // Open our tiff image
4515 if( !(tif = TIFFOpen(fileName.c_str(), "r")))
4516 return 1;
4517
4518 // All these tags are required -- bail if any are missing.
4519 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wTIFF))
4520 return 2;
4521 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hTIFF))
4522 return 3;
4523 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &sppTIFF))
4524 return 4;
4525 if( 1 != TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &pcTIFF))
4526 return 5;
4527 if( 1 != TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &pmTIFF))
4528 return 6;
4529 if( 1 != TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpsTIFF))
4530 return 7;
4531
4532 // This one is not required. If it's missing, it's 1 (unsigned integer).
4533 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &fmtTIFF))
4534 fmtTIFF = 1;
4535
4536 // MJR TODO NOTE We don't know how to deal with pallet images (pmTIFF == PHOTOMETRIC_PALETTE). Should check for that.
4537 // MJR TODO NOTE We don't know how to deal with tiled images. Should check for that.
4538
4539 //uint64_t cmTIFF = (1ULL << bpsTIFF) - 1ULL;
4540
4541 // // Dump out image metadata
4542 // std::cerr << "TIFF: " << fileName << std::endl;
4543 // std::cerr << " T WIDTH: " << wTIFF << std::endl;
4544 // std::cerr << " T HEIGHT: " << hTIFF << std::endl;
4545 // std::cerr << " T SPP: " << sppTIFF << std::endl;
4546 // std::cerr << " T PLNC: " << pcTIFF << std::endl;
4547 // std::cerr << " T PHOM: " << pmTIFF << std::endl;
4548 // std::cerr << " T BPS: " << bpsTIFF << std::endl;
4549 // std::cerr << " T MAX: " << cmTIFF << std::endl;
4550 // std::cerr << " T FMT: " << fmtTIFF << std::endl;
4551
4552 // Check file image size and reallocate aRamCanvas
4553 if(wTIFF < 1)
4554 return 8;
4555
4556 if(hTIFF < 1)
4557 return 9;
4558
4559 resizeCanvas(wTIFF, hTIFF);
4560
4561 uint32_t wRC = getNumPixX();
4562
4563 if ((pcTIFF != PLANARCONFIG_CONTIG) && (pcTIFF != PLANARCONFIG_SEPARATE))
4564 return 22;
4565
4566 if(wTIFF != wRC)
4567 return 12;
4568
4569 uint32_t hRC = getNumPixY();
4570
4571 if(hTIFF != hRC)
4572 return 14;
4573
4574 uint16_t sppRC = colorT::channelCount;
4575
4576 if(sppTIFF != sppRC)
4577 return 19;
4578
4579 uint16_t bpsRC = colorT::bitsPerPixel / sppRC;
4580
4581 if(bpsTIFF != bpsRC)
4582 return 20;
4583
4584 // We only suport SAMPLEFORMAT_UINT & SAMPLEFORMAT_IEEEFP
4585 if ((fmtTIFF != SAMPLEFORMAT_UINT) && (fmtTIFF != SAMPLEFORMAT_IEEEFP))
4586 return 18;
4587
4588 if (( colorType::chanIsInt && (SAMPLEFORMAT_UINT != 1)) ||
4589 (!(colorType::chanIsInt) && (SAMPLEFORMAT_IEEEFP != 3)))
4590 return 21;
4591
4592 bool yNat = !(isIntAxOrientationNaturalY());
4593 bool xNat = isIntAxOrientationNaturalX();
4594 tsize_t scanlinesize = TIFFScanlineSize(tif);
4595 tdata_t scanLineBuffer = _TIFFmalloc(scanlinesize);
4596
4597 if(scanLineBuffer == NULL)
4598 return 16;
4599
4600 if (pcTIFF == PLANARCONFIG_CONTIG) { // Chunky
4601 for(uint32_t row=0; row<hTIFF; row++) {
4602 if( !(TIFFReadScanline(tif, scanLineBuffer, row)))
4603 return 17;
4604 char* p = (char*)(scanLineBuffer);
4605 for(uint32_t col=0; col<wTIFF; col++) {
4606 int x = (xNat ? col : wTIFF-col-1);
4607 int y = (yNat ? row : hTIFF-row-1);
4608 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4609 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4610 p = p + (bpsTIFF/8);
4611 }
4612 }
4613 }
4614 } else if (pcTIFF == PLANARCONFIG_SEPARATE) { // planar
4615 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4616 for(uint32_t row=0; row<hTIFF; row++) {
4617 if( !(TIFFReadScanline(tif, scanLineBuffer, row, samp)))
4618 return 17;
4619 char* p = (char*)(scanLineBuffer);
4620 for(uint32_t col=0; col<wTIFF; col++) {
4621 int x = (xNat ? col : wTIFF-col-1);
4622 int y = (yNat ? row : hTIFF-row-1);
4623 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4624 p = p + (bpsTIFF/8);
4625 }
4626 }
4627 }
4628 }
4629
4630 _TIFFfree(scanLineBuffer);
4631 TIFFClose(tif);
4632 return 0;
4633#endif
4634 }
4635
4636////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4637 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4638 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4639 inline bool
4641#ifndef MRASTER_FOUND_TIFF
4642 return true;
4643#else
4644 return false;
4645#endif
4646 }
4647
4648////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4649 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4650 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4653 double Xo,
4654 double Yo,
4655 double oScale,
4656 colorArgType errorColor,
4657 interpolationType interpMethod) {
4658 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4659 for(intCrdT y=0; y<numPixY; y++) {
4660 for(intCrdT x=0; x<numPixX; x++) {
4661 double xT = (x-Xo);
4662 double yT = (y-Yo);
4663 mjr::point2d<double> fv = f(xT, yT);
4664 double xS = fv.x / oScale + Xo;
4665 double yS = fv.y / oScale + Yo;
4666 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4667 newRamCanvas.drawPointNC(x, y, errorColor);
4668 } else {
4669 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4670 }
4671 }
4672 }
4673 return newRamCanvas;
4674 }
4675
4676////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4677 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4678 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4681 double Xo,
4682 double Yo,
4683 double oScale,
4684 colorArgType errorColor,
4685 interpolationType interpMethod) {
4686 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4687 for(intCrdT y=0; y<numPixY; y++) {
4688 for(intCrdT x=0; x<numPixX; x++) {
4689 double xT = x-Xo;
4690 double yT = y-Yo;
4691 double xS = (HAMatrix[0] * xT + HAMatrix[1] * yT + HAMatrix[2]) / oScale + Xo;
4692 double yS = (HAMatrix[3] * xT + HAMatrix[4] * yT + HAMatrix[5]) / oScale + Yo;
4693 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4694 newRamCanvas.drawPointNC(x, y, errorColor);
4695 } else {
4696 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4697 }
4698 }
4699 }
4700 return newRamCanvas;
4701 }
4702
4703////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4704 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4705 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4708 double rScale,
4709 double Xo,
4710 double Yo,
4711 double oScale,
4712 colorArgType errorColor,
4713 interpolationType interpMethod) {
4714 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4715 for(intCrdT y=0; y<numPixY; y++) {
4716 for(intCrdT x=0; x<numPixX; x++) {
4717 double xT = (x - Xo);
4718 double yT = (y - Yo);
4719 double rT = std::hypot(xT, yT) / rScale;
4720 // TODO: Use mjr::evalUniPoly
4721 double rS = RPoly[0];
4722 for (unsigned int i=1; i<RPoly.size(); i++)
4723 rS = rS*rT + RPoly[i];
4724 double xS = xT * rS / oScale + Xo;
4725 double yS = yT * rS / oScale + Yo;
4726 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4727 newRamCanvas.drawPointNC(x, y, errorColor);
4728 } else {
4729 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4730 }
4731 }
4732 }
4733 return newRamCanvas;
4734 }
4735
4736////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4737 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4738 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4741 std::vector<double> const& BiPolyY,
4742 double Xo,
4743 double Yo,
4744 double oScale,
4745 colorArgType errorColor,
4746 interpolationType interpMethod) {
4747 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4748 for(intCrdT y=0; y<numPixY; y++) {
4749 for(intCrdT x=0; x<numPixX; x++) {
4750 double xT = (x-Xo);
4751 double yT = (y-Yo);
4752 double xS = mjr::math::bply::eval(BiPolyX, xT, yT) / oScale + Xo;
4753 double yS = mjr::math::bply::eval(BiPolyY, xT, yT) / oScale + Yo;
4754 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4755 newRamCanvas.drawPointNC(x, y, errorColor);
4756 } else {
4757 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4758 }
4759 }
4760 }
4761 return newRamCanvas;
4762 }
4763
4764} // end namespace mjr
4765
4766#define MJR_INCLUDE_ramCanvasTpl
4767#endif
User include file for color types.
Internal include file for ramCanvas types.
Template Class used to house colors for ramCanvas objects.
static constexpr herChar chars[3935]
Data for each hershey font
font
Enum for hershey font names.
static constexpr int ascii2hershey[5][95]
ASCII to Hershey Character Number mapping array.
Handy class to hold a point in 2D (integer or real)
Definition MRpoint2d.hpp:46
coordT x
X coordinate.
Definition MRpoint2d.hpp:48
coordT y
Y coordinate.
Definition MRpoint2d.hpp:49
Colorize a ramCanvasTpl with integer channels using a color scheme.
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
This class is an incomplete rcConverter (no getPxColorNC method) that provides a nice base for homoge...
inRamCanvasT::coordIntType getNumPixX()
inRamCanvasT::coordIntType getNumPixY()
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
Convert a ramCanvasTpl to a greyscale image using colorT::intensity().
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBAbyte colorType
inRamCanvasT::colorType::colConRGBAdbl colorType
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBbyte colorType
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBdbl colorType
Class providing off-screen drawing functionality.
void drawRectangle(pointFltType *thePoints)
interpolationType
Enum for drawing Mode.
void setRealAxOrientationY(realAxisOrientation orientation)
Set the real Y axis orientation.
void drawPoint(fltCrdT x, fltCrdT y)
pointIntType real2int(intCrdT x, intCrdT y)
Convert integer x & y coordinates to real x & y coordinates.
void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3)
void drawLine(pointFltType point1)
void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color)
pointFltType int2corner(intCrdT x, intCrdT y, int cornerIndex)
Given integer x & y coordinates and a corner index, produce real x & y coordinates for one of the pix...
intAxisOrientation getIntAxOrientationY()
Is the integer Y axis orientation NATURAL?
fltCrdT getCanvasWidY()
height of the display(real coord)
void drawFillRectangle(pointIntType *thePoints, colorArgType color)
void drawFillRectangle(pointFltType point1, pointFltType point2, colorArgType color)
void drawFillCircle(pointIntType centerPoint, intCrdT radiusX)
colorT::cornerColorEnum colorCornerEnum
colorT: RGB Color Corners
void drawFillRectangle(pointIntType *thePoints)
pointFltType int2real(intCrdT x, intCrdT y)
Convert real x & y coordinates to integer x & y coordinates.
colorT::csNatType csNatType
colorT: Color Scheme Natural Type
void drawLine(pointFltType point1, pointFltType point2, colorArgType color)
intCrdT statNumNonZeroPixels()
void moveTo(pointIntType thePoint)
void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor)
void adjoinCanvasRight(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
endianType
Endianness Identifiers.
drawModeType drawMode
Drawing mode.
int isOnCanvas(fltCrdT x, fltCrdT y) const
Determine if the given point is within the bounds of the ramCanvasTpl.
void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color)
realAxisOrientation
Enum for real axis orientation.
void drawFillTriangle(pointFltType *thePoints)
void drawPoint(fltCrdT x, fltCrdT y, colorArgType color)
void drawFillTriangle(pointIntType *thePoints)
void drawTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3)
void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX)
void drawFillTriangle(pointFltType *thePoints, colorArgType color)
intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color)
void drawLine(pointFltType point1, pointFltType point2)
intAxisOrientation intAxOrientationX
Flip horizontally.
void drawPoint(intCrdT x, intCrdT y)
void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3)
void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
drawModeType
Enum for drawing Mode.
void setDefaultDrawMode()
Set the default draw mode.
fltCrdT canvasWidY
height of the canvas (real coord)
void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3)
void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color)
colorT dfltColor
Default color.
void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc)
void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3)
fltCrdT canvasWidX
Width of the canvas (real coord)
void drawLine(pointIntType point1)
void drawTriangle(pointIntType *thePoints, colorArgType color)
void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
colorT getPxColor(intCrdT x, intCrdT y) const
Returns a copy of the color at the given coordinates.
void drawFillTriangle(pointIntType *thePoints, colorArgType color)
intCrdT dfltY
y coordinate used by default.
colorT::colorRefType colorRefType
colorT: Ref to a color
colorT * pixels
Array to hold the color values.
fltCrdT minRealX
x coord of min (real coord)
intCrdT realDelta2intX(fltCrdT x) const
Convert real distance on the x coordinate axis to an integral distance.
fltCrdT getCanvasWidD()
Width of the display (real coord)
void setDfltColor(std::string cornerColor)
void setDrawMode(drawModeType newDrawMode)
Set the current drawing mode NOOP if enableDrawModes is false.
void setDfltColor(const char *cornerColor)
colorT::channelArithFltType colorChanArithFltType
colorT: Channel arithmatic (Flt: +-*)
void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3, colorArgType color)
void drawRectangle(pointIntType *thePoints, colorArgType color)
colorT * pixelIterator
pixel store iterators
void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color)
intAxisOrientation getIntAxOrientationX()
Get the integer X axis orientation.
void drawPointS(intCrdT x, intCrdT y, colorArgType color)
Draw a point without any special drawing options.
void drawPoint(pointIntType thePoint)
void drawLine(pointIntType point1, pointIntType point2)
void setRealAxOrientationX(realAxisOrientation orientation)
Set the real X axis orientation.
void moveTo(pointFltType thePoint)
fltCrdT maxRealX
x coord of max (real coord)
bool isNotSameSize(ramCanvasTpl const &inRC) const
Return true if given canvas and current canvas are NOT the same size.
fltCrdT getMaxRealY()
y coord of max (real coord)
realAxisOrientation getRealAxOrientationX()
Get the real X axis orientation.
void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color)
void drawHorzLineNC(intCrdT xMin, intCrdT xMax, intCrdT yConst, colorArgType color)
Draw a horizontal line with no clipping or bounds checking.
fltCrdT minRealY
y coord of min (real coord)
void setDfltColor(colorArgType color)
Set the default color.
void moveTo(intCrdT x, intCrdT y)
Set the current default point to the given coordinates.
void drawCircle(pointFltType centerPoint, fltCrdT radiusX)
colorT * pixelsE
Point one beyond end of pixels array.
void drawTriangle(pointFltType *thePoints, colorArgType color)
fltCrdT getMaxRealX()
x coord of max (real coord)
realAxisOrientation realAxOrientationX
Orientation of x axis.
colorT::maskType colorMaskType
colorT: Mask type
void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color)
void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color)
fltCrdT maxRealY
y coord of max (real coord)
bool isIntAxOrientationNaturalY()
Get the integer Y axis orientation.
void drawFillCircle(fltCrdT radiusX)
int isCliped(intCrdT x, intCrdT y) const
colorT::colorArgType colorArgType
colorT: Argument passing type
void drawPointNC(intCrdT x, intCrdT y, colorArgType color)
The functions here work in a similar way to the non-NC functions, but with no clipping or bounds chec...
point2d< intCrdT > pointIntType
Integer coordinate pair type.
fltCrdT pixWidY
Height of a pixel (real coord)
void drawRectangle(pointFltType *thePoints, colorArgType color)
void setRealAxisDefaultOrientation()
Set the real axis orientation to default (NATURAL for both X and Y axes)
void drawStringBox(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc)
colorT getPxColor(fltCrdT x, fltCrdT y) const
colorT * iterator
pixel store iterators
fltCrdT coordFltType
Real type for coordinates.
std::complex< fltCrdT > cplxFltType
Real coordinate complex type (Provided for convince – not used in ramCanvasTpl)
void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3)
void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color)
fltCrdT getPixWidX()
Width of a pixel (real coord)
void drawFillRectangle(pointFltType point1, pointFltType point2)
colorT::channelArithSDPType colorChanArithSDPType
colorT: Channel arithmatic (Int: +-*)
void drawRectangle(pointFltType point1, pointFltType point2)
void drawTriangle(pointFltType *thePoints)
colorT::colorPtrType colorPtrType
colorT: Pointer to color
void drawCircle(pointIntType centerPoint, intCrdT radiusX)
void setDfltColor(colorChanType r, colorChanType g, colorChanType b)
colorT::channelArithSPType colorChanArithSPType
colorT: Channel arithmatic (Int: +*)
void drawLine(pointIntType point1, pointIntType point2, colorArgType color)
void drawPoint(pointFltType thePoint)
intCrdT numPixX
Number of x pixels.
point2d< fltCrdT > pointFltType
Real coordinate pair type.
realAxisOrientation realAxOrientationY
Orientation of y axis.
int isCliped(fltCrdT x, fltCrdT y) const
Determine if the given point is within the bounds of the ramCanvasTpl.
void drawRectangle(pointIntType point1, pointIntType point2, colorArgType color)
void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX)
intAxisOrientation intAxOrientationY
Flip vertically.
void combineRamCanvasMean(ramCanvasTpl *theCanvasList, const int N)
Take a list of ramCanvasTpl objects and combine them with the current ramCanvasTpl using mean.
colorT colorType
Color type for pixels.
void moveTo(fltCrdT x, fltCrdT y)
void setIntAxOrientationX(intAxisOrientation orientation)
Set the integer X axis orientation.
intCrdT realDelta2intY(fltCrdT y) const
Convert real distance on the y coordinate axis to an integral distance.
intCrdT numPixY
Number of y pixels.
void drawLine(fltCrdT x, fltCrdT y, colorArgType color)
fltCrdT getCanvasWidX()
Width of the display (real coord)
void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color)
void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3)
pointFltType int2corner(intCrdT x, intCrdT y, int cornerX, int cornerY)
Given integer x & y coordinates, produce real x & y coordinates for one of the pixel's corners.
void insertCanvas(const ramCanvasTpl &theCanvas, intCrdT x1=0, intCrdT y1=0)
Draw the given canvas at the indicated point.
void drawCircle(fltCrdT radiusX)
colorT::cmfInterpolationEnum cmfInterpolationEnum
colorT: Interpolation for color match functions
colorT getPxColorNC(intCrdT x, intCrdT y) const
Get the default point to the specified coordinates with no clipping or bounds checking.
colorT::colorSpaceEnum colorSpaceEnum
colorT: Color spaces
void drawFillRectangle(pointFltType *thePoints, colorArgType color)
void drawLine(pointFltType point1, colorArgType color)
void adjoinCanvasLeft(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
bool isIntAxOrientationNaturalX()
Is the integer X axis NATURAL?
colorT getPxColor(pointIntType thePoint) const
fltCrdT pixWidX
Width of a pixel (real coord)
colorT getPxColor(pointFltType thePoint) const
void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2)
void drawRectangle(pointIntType *thePoints)
bool isSameSize(ramCanvasTpl const &inRC) const
Return true if given canvas and current canvas are the same size.
void drawLine(intCrdT x, intCrdT y)
void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX)
void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX)
void drawVertLineNC(intCrdT yMin, intCrdT yMax, intCrdT xConst, colorArgType color)
Draw a vertical line with no clipping or bounds checking.
void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2)
void drawFillRectangle(pointFltType *thePoints)
void drawLine(fltCrdT x, fltCrdT y)
fltCrdT intDelta2realY(intCrdT y) const
Convert integral distance on the y coordinate to a real distance.
void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3)
void drawPoint(pointFltType thePoint, colorArgType color)
void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color)
void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX)
int isOnCanvas(intCrdT x, intCrdT y) const
intCrdT coordIntType
Integer type for coordinates.
void drawPoint(colorArgType color)
void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color)
intCrdT dfltX
x coordinate used by default.
fltCrdT getPixWidY()
Height of a pixel (real coord)
void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color)
realAxisOrientation getRealAxOrientationY()
Get the real Y axis orientation.
bool isClose(ramCanvasTpl const &inRC, colorChanType epsilon) const
Return true if corresponding pixels in each canvas are "close" as defined by colorTpl::isClose().
void drawCircle(intCrdT radiusX)
void drawTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color)
intCrdT getNumPixX() const
intCrdT getNumPixY() const
std::complex< intCrdT > cplxIntType
Integer coordinate complex type (Provided for convince – not used in ramCanvasTpl)
fltCrdT getMinRealX()
x coord of min (real coord)
void drawRectangle(pointIntType point1, pointIntType point2)
void drawTriangle(pointIntType *thePoints)
void drawPoint(intCrdT x, intCrdT y, colorArgType color)
Draw a point at the specified coordinates with the specified color.
void setIntAxOrientationY(intAxisOrientation orientation)
Set the integer Y axis orientation.
colorT::channelArithLogType colorChanArithLogType
colorT: Channel arithmatic (Int: ^|&~)
colorT::csFltType csFltType
colorT: Color Scheme Float Type
void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2)
drawModeType getDrawMode()
Get the current drawing mode.
void drawFillCircle(intCrdT radiusX)
void adjoinCanvasBottom(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
intCrdT numPix
Number of pixels.
colorT::channelType colorChanType
colorT: Channel type
void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color)
colorT::csIntType csIntType
colorT: Color Scheme Integer Type
colorT::channelArithDType colorChanArithDType
colorT: Channel arithmatic (Int: -)
void drawPoint(pointIntType thePoint, colorArgType color)
void drawFillRectangle(pointIntType point1, pointIntType point2)
intAxisOrientation
Enum for integer axis orientation.
colorT * getPixels()
Returns a pointer to the raw pixel store.
fltCrdT intDelta2realX(intCrdT x) const
Convert integral distance on the x coordinate to a real distance.
void adjoinCanvasTop(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
bool isEqual(ramCanvasTpl const &inRC) const
Return true if corresponding pixels in each canvas are "equal" as defined by colorTpl::isEqual().
void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3, colorArgType color)
colorT::colorCRefType colorCRefType
colorT: Const Ref to a color
void drawLine(intCrdT x, intCrdT y, colorArgType color)
colorT & getPxColorRefNC(intCrdT x, intCrdT y) const
Returns a reference to the color object for the given pixel with no clipping or bounds checking.
void setIntAxisDefaultOrientation()
Set the integer axis orientation to default (NATURAL for both X and Y axes)
fltCrdT getMinRealY()
y coord of min (real coord)
void drawLine(pointIntType point1, colorArgType color)