MRaster lib 22.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"
41
42#include "MRMathIVL.hpp"
43#include "MRMathFC.hpp"
44#include "MRMathODR.hpp"
45#include "MRMathBPLY.hpp"
46
47////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
48#ifdef MRASTER_FOUND_TIFF
49#include <unistd.h> /* UNIX std stf POSIX */
50#include <tiffio.h> /* libTIFF libTIFF */
51#endif
52
53////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
54#include <algorithm> /* STL algorithm C++11 */
55#include <chrono> /* time C++11 */
56#include <cmath> /* std:: C math.h C++11 */
57#include <complex> /* Complex Numbers C++11 */
58#include <cstdint> /* std:: C stdint.h C++11 */
59#include <fstream> /* C++ fstream C++98 */
60#include <functional> /* STL funcs C++98 */
61#include <iomanip> /* C++ stream formatting C++11 */
62#include <iostream> /* C++ iostream C++11 */
63#include <iterator> /* STL Iterators C++11 */
64#include <list> /* STL list C++11 */
65#include <map> /* STL map C++11 */
66#include <numbers> /* C++ math constants C++20 */
67#include <random> /* C++ random numbers C++11 */
68#include <sstream> /* C++ string stream C++ */
69#include <stdexcept> /* Exceptions C++11 */
70#include <string> /* C++ strings C++11 */
71#include <type_traits> /* C++ metaprogramming C++11 */
72#include <utility> /* STL Misc Utilities C++11 */
73#include <vector> /* STL vector C++11 */
74
75////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
76// Put everything in the mjr namespace
77namespace mjr {
78 /** @brief Class providing off-screen drawing functionality.@EOL
79
80 This class essentially manages a 2D array of pixels (represented as colorTpl objects). Both integer and floating point coordinates are supported.
81
82 Coordinates
83 ===========
84
85 Traditional Mathematical Coordinate System
86 ------------------------------------------
87
88 The traditional coordinate system used in mathematics is the Cartesian Coordinate system. In this system the axes represent real numbers which increase as
89 one moves to the right or up.
90
91
92 ^ y (increasing upward)
93 |
94 . (0, 1)
95 |
96 |
97 |
98 (-1,0) | (0,0) x (increasing to the right)
99 <-.--------+--------.----->
100 | (1,0)
101 |
102 |
103 |
104 . (0, -1)
105 |
106 v
107
108 Traditional Computer Graphics Coordinate System
109 -----------------------------------------------
110
111 Unlike the Cartesian coordinate system, the traditional coordinates used in computer graphics have only positive, integer coordinates, the origin at the upper
112 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
113 typical layout of 2D arrays in RAM.
114
115
116 (0,0) +------------+ (numPixX-1, 0)
117 | |
118 | |
119 | |
120 | |
121 | |
122 (numPixY-1, 0) +------------+ (numPixX-1, numPixY-1)
123
124 ramCanvas Coordinate Systems
125 ----------------------------
126
127 This library supports two sets of coordinates for each image:
128
129 - Integer -- much like traditional computer graphics coordinates
130 - Floating Point -- much like mathematical coordinates
131
132 The integer coordinates are a generalization of the traditional integer coordinates used for computer graphics. Like the traditional system, they are
133 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
134 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
135 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
136 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
137 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
138 writeRAWfile.
139
140 @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
141 @tparam colorT A type for the image pixels (a color)
142 @tparam fltCrdT A floating point type used for the floating point image coordinates
143 @tparam enableDrawModes If true, enables drawing modes other than drawModeType::SET. */
144 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
145 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
147 public:
148
149 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150 /** @name Typedefs related to template parameters */
151 //@{
152 typedef point2d<fltCrdT> pointFltType; //!< Real coordinate pair type
153 typedef point2d<intCrdT> pointIntType; //!< Integer coordinate pair type
154 typedef std::vector<pointIntType> pointIntVecType; //!< Integer coordinate pair type
155 typedef std::complex<fltCrdT> cplxFltType; //!< Real coordinate complex type (Provided for convince -- not used in ramCanvasTpl)
156 typedef std::complex<intCrdT> cplxIntType; //!< Integer coordinate complex type (Provided for convince -- not used in ramCanvasTpl)
157 typedef intCrdT coordIntType; //!< Integer type for coordinates
158 typedef fltCrdT coordFltType; //!< Real type for coordinates
159 typedef colorT colorType; //!< Color type for pixels
160 //@}
161
162 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
163 /** @name std::function typedefs for common calls. */
164 //@{
165 typedef std::function<colorT (fltCrdT, fltCrdT)> fltCrd2ColType; //!< std::function type floating point coordinates to a color
166 typedef std::function<colorT (pointFltType)> fltPnt2ColType; //!< std::function type floating point point to a color
167 typedef std::function<colorT (intCrdT, intCrdT)> intCrd2ColType; //!< std::function type int point coordinates to a color
168 typedef std::function<colorT (pointIntType)> intPnt2ColType; //!< std::function type int point point to a color
169 //@}
170
171 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172 /** @name Typedefs related to colorT */
173 //@{
174 typedef typename colorT::channelType colorChanType; //!< colorT: Channel type
175 typedef typename colorT::maskType colorMaskType; //!< colorT: Mask type
176 typedef typename colorT::channelArithDType colorChanArithDType; //!< colorT: Channel arithmatic (Int: -)
177 typedef typename colorT::channelArithSPType colorChanArithSPType; //!< colorT: Channel arithmatic (Int: +*)
178 typedef typename colorT::channelArithSDPType colorChanArithSDPType; //!< colorT: Channel arithmatic (Int: +-*)
179 typedef typename colorT::channelArithFltType colorChanArithFltType; //!< colorT: Channel arithmatic (Flt: +-*)
180 typedef typename colorT::channelArithLogType colorChanArithLogType; //!< colorT: Channel arithmatic (Int: ^|&~)
181 typedef typename colorT::colorSpaceEnum colorSpaceEnum; //!< colorT: Color spaces
182 typedef typename colorT::cornerColorEnum colorCornerEnum; //!< colorT: RGB Color Corners
183 typedef typename colorT::colorArgType colorArgType; //!< colorT: Argument passing type
184 typedef typename colorT::colorPtrType colorPtrType; //!< colorT: Pointer to color
185 typedef typename colorT::colorRefType colorRefType; //!< colorT: Ref to a color
186 typedef typename colorT::colorCRefType colorCRefType; //!< colorT: Const Ref to a color
187 typedef typename colorT::csIntType csIntType; //!< colorT: Color Scheme Integer Type
188 typedef typename colorT::csFltType csFltType; //!< colorT: Color Scheme Float Type
189 typedef typename colorT::csNatType csNatType; //!< colorT: Color Scheme Natural Type
190 typedef typename colorT::cmfInterpolationEnum cmfInterpolationEnum; //!< colorT: Interpolation for color match functions
191 //@}
192
193 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194 /** @name Iterator Typedefs */
195 //@{
196 typedef colorT* pixelIterator; //!< pixel store iterators
197 typedef colorT* iterator; //!< pixel store iterators
198 //@}
199
200 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201 /** @name Enumerations */
202 //@{
203 /** Enum for real axis orientation */
204 enum class realAxisOrientation { INVERTED, //!< Real axis is inverted with respect to the integer axis
205 NATURAL //!< Real axis is not inverted with respect to the integer axis
206 };
207
208 /** Enum for integer axis orientation.
209
210 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
211 array. The integer axis orientation is used to arrange the pixels when a canvas is saved/loaded to/from an image file. */
212 enum class intAxisOrientation { INVERTED, //!< Zero is to the right or bottom
213 NATURAL //!< Zero is to the left or top
214 };
215
216 /** Enum for drawing Mode */
217 enum class drawModeType { SET, //!< Simply set the pixel value to the new value
218 XOR, //!< See: tfrmXor()
219 ADDCLAMP, //!< See: tfrmAddClamp()
220 AND, //!< See: tfrmAnd()
221 OR, //!< See: tfrmOr()
222 DIFFCLAMP, //!< See: tfrmDiffClamp()
223 MULTCLAMP //!< See: tfrmMultClamp()
224 };
225
226 /** Enum for drawing Mode */
227 enum class interpolationType { BILINEAR, //!< bilinear
228 TRUNCATE, //!< Coordinates are truncated (fractional bits chopped off)
229 NEAREST, //!< Coordinates are rounded
230 AVERAGE4, //!< Average of four sourounding pixels
231 AVERAGE9 //!< Average of 9 sourounding pixels
232 };
233
234 //@}
235
236 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
237 /** @name Logical Maximum for intCrdT values */
238 //@{
239 const static intCrdT intCrdMax = (1ul << ((sizeof(intCrdT)*CHAR_BIT-1)/2)) - 3; //!< maximum for numPixX, numPixY, & numPix.
240 //@}
241
242 private:
243
244 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
245 /** @name Private Enumerations */
246 //@{
247 /** Endianness Identifiers. */
248 enum class endianType {
249 BIG, //!< PowerPC
250 LITTLE, //!< Intel
251 AUTO //!< Whatever the platform uses
252 };
253 //@}
254
255 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
256 /** @name intCrd Guard Valus */
257 //@{
258 const static intCrdT intCrdGrdMax = intCrdMax+1; //!< Large sentinel value (always off canvas)
259 const static intCrdT intCrdGrdMin = -1; //!< Small sentinel value (always off canvas)
260 //@}
261
262 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
263 /** @name Canvas integer coordinates */
264 //@{
265 intCrdT numPixX; //!< Number of x pixels
266 intCrdT numPixY; //!< Number of y pixels
267 intCrdT numPix; //!< Number of pixels
268 //@}
269
270 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
271 /** @name Canvas real coordinates */
272 //@{
273 fltCrdT minRealX; //!< x coord of min (real coord)
274 fltCrdT maxRealX; //!< x coord of max (real coord)
275 fltCrdT minRealY; //!< y coord of min (real coord)
276 fltCrdT maxRealY; //!< y coord of max (real coord)
277 //@}
278
279 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
280 /** @name Canvas real/integer coordinates conversion */
281 //@{
282 fltCrdT pixWidX; //!< Width of a pixel (real coord)
283 fltCrdT pixWidY; //!< Height of a pixel (real coord)
284
285 fltCrdT canvasWidX; //!< Width of the canvas (real coord)
286 fltCrdT canvasWidY; //!< height of the canvas (real coord)
287 //@}
288
289 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
290 /** @name Axis orientation */
291 //@{
292 realAxisOrientation realAxOrientationX; //!< Orientation of x axis
293 realAxisOrientation realAxOrientationY; //!< Orientation of y axis
294 intAxisOrientation intAxOrientationX; //!< Flip horizontally
296 //@}
297
298 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
299 /** @name Canvas pixel store pointers */
300 //@{
301 colorT *pixels; //!< Array to hold the color values.
302 colorT *pixelsE; //!< Point one beyond end of pixels array.
303 //@}
304
305 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
306 /** @name Drawing defaults */
307 //@{
308 colorT dfltColor; //!< Default color.
309 drawModeType drawMode; //!< Drawing mode.
310 intCrdT dfltX; //!< x coordinate used by default.
311 intCrdT dfltY; //!< y coordinate used by default.
312 //@}
313
314 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
315 /** @name Filled Triangle Utility Functions */
316 //@{
317 //--------------------------------------------------------------------------------------------------------------------------------------------------------
318 /** Utliity function behind the drawFillTriangle() functions.
319 @bug Not thread safe
320 @param x1 The x coordinate of the first point
321 @param y1 The y coordinate of the first point
322 @param x2 The x coordinate of the second point
323 @param y2 The y coordinate of the second point
324 @param x3 The x coordinate of the third point
325 @param y3 The y coordinate of the third point
326 @param c1 The color of the first point (x1, y1)
327 @param c2 The color of the second point (x2, y2)
328 @param c3 The color of the third point (x3, y3)
329 @param solid Use only c1 if true, otherwise use barycentric interpolation */
330 void drawFillTriangleUtl(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorT c1, colorT c2, colorT c3, bool solid);
331 //@}
332
333 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
334 /** @name File Writing Utility Methods */
335 //@{
336 //--------------------------------------------------------------------------------------------------------------------------------------------------------
337 /** Write an unsigned integer to a stream with given length and endianness.
338 @param oStream The ostream object to which to write
339 @param endianness The endianness to use for the integer.
340 @param numBytes The number of bytes of the data parameter to use (logically the least significant bits)
341 @param data The integer to write */
342 void writeUIntToStream(std::ostream& oStream, endianType endianness, int numBytes, uint64_t data);
343 //--------------------------------------------------------------------------------------------------------------------------------------------------------
344 /** Determine the platform's endianness. */
346 //@}
347
348 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
349 /** @name Coordinate System Manipulation (i) */
350 //@{
351 //--------------------------------------------------------------------------------------------------------------------------------------------------------
352 /** Several internal parameters are maintained within this class that make conversion between real coordinates and integer coordinate very fast. This
353 function will update the internal parameters if the real coordinate sizes or the integer coordinate sizes have changed. This function is intended for
354 internal use. An example of when to use this function is right after the integer coordinate axes have changed via a call to newIntCoordsNC(). */
356 //--------------------------------------------------------------------------------------------------------------------------------------------------------
357 /** Change the logical coordinate sizes.
358 It is important that the specified coordinate sizes describe an image with FEWER pixels than the previous sizes. This function will NOT allocate a
359 new pixel array, so the previous array contents will be interpreted as valid data -- just at different coordinates. This function causes no memory
360 leaks. This function will NOT update the internal parameters related to real coordinate systems and so updRealCoords() should be called after this
361 function in most cases. This function is intended for internal use and provides no safety checks.
362 @param numPixX_p The width of the new canvas
363 @param numPixY_p The height of the new canvas */
364 void newIntCoordsNC(intCrdT numPixX_p, intCrdT numPixY_p);
365 //@}
366
367 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
368 /** @name Plane Manipulation Methods */
369 //@{
370 //--------------------------------------------------------------------------------------------------------------------------------------------------------
371 /** Destroy the current pixel memory and reallocate a new pixel space of the given size.
372 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
373 new canvas if either argument is zero or less. Updates coordinates.
374 @param numPixX_p The width of the new canvas
375 @param numPixY_p The height of the new canvas */
376 void reallocCanvas(intCrdT numPixX_p, intCrdT numPixY_p);
377 //--------------------------------------------------------------------------------------------------------------------------------------------------------
378 /** Free the pixel memory (i) */
380 //--------------------------------------------------------------------------------------------------------------------------------------------------------
381 /** Points the pixels pointer at a new pixel store, and updates coordinates. Pixels pointer not changed if new_pixels is NULL */
382 void rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY);
383 //@}
384
385 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
386 /** @name Various helper functions */
387 //@{
388 //--------------------------------------------------------------------------------------------------------------------------------------------------------
389 /** Used to find the left and right edges of a triangle. */
390 void triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin);
391 //@}
392
393 public:
394
395 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
396 /** @name Raster Data Import And Export. */
397 //@{
398 //--------------------------------------------------------------------------------------------------------------------------------------------------------
399 /** Extract raster data from the image, and pack it into a typical form used by imaging applications.
400
401 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.
402 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
403 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
404 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,
405 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:
406
407 Examples of how to pack various common raster data formats
408 ..........RGB RGBA ARGB BGR ABGR Grey
409 redChan 0 0 1 2 3 0
410 greenChan 1 1 2 1 2 -1
411 blueChan 2 2 3 0 1 -1
412 alphaChan -1 3 0 -1 0 -1
413
414 @param rasterData Unsigned char pointer to image data. If NULL,then data will be allocated for image.
415 @param x1 First x coordinate first corner of sub-image to extract
416 @param x2 First x coordinate second corner of sub-image to extract
417 @param y1 First y coordinate first corner of sub-image to extract
418 @param y2 First y coordinate second corner of sub-image to extract
419 @param redChan Channel index to use for red
420 @param blueChan Channel index to use for blue
421 @param greenChan Channel index to use for green
422 @param alphaChan Channel index to use for alpha*/
423 int exportRasterData(void* &rasterData, intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, int redChan, int greenChan, int blueChan, int alphaChan);
424 //@}
425
426 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
427 /** @name Constructors & Assignment Operators */
428 //@{
429 //--------------------------------------------------------------------------------------------------------------------------------------------------------
430 /** No arg constructor. Sets numPixX and numPixY to -1, and pixels to NULL. */
432 //--------------------------------------------------------------------------------------------------------------------------------------------------------
433 /** Copy constructor */
434 ramCanvasTpl(const ramCanvasTpl &theCanvas);
435 //--------------------------------------------------------------------------------------------------------------------------------------------------------
436 /** Most commonly used constructor.
437 The real coordinates have default values with -1 as the min values and 1 used as the max values.
438 @param numPixX_p Number of pixels in the X direction
439 @param numPixY_p Number of pixels in the Y direction
440 @param minRealX_p Minimum real x coordinate value
441 @param maxRealX_p Maximum real x coordinate value
442 @param minRealY_p Minimum real y coordinate value
443 @param maxRealY_p Maximum real y coordinate value */
444 ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p=-1, fltCrdT maxRealX_p=1, fltCrdT minRealY_p=-1, fltCrdT maxRealY_p=1);
445 //--------------------------------------------------------------------------------------------------------------------------------------------------------
446 /** Move constructor */
448 //--------------------------------------------------------------------------------------------------------------------------------------------------------
449 /** Move assignment operator */
451 //@}
452
453 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
454 /** @name Destructor */
455 //@{
456 /** Destructor deallocates memory for the canvas. */
458 //@}
459
460
461 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
462 /** @name Canvas Compositing
463
464 @warning These functions are experimental! Functionality and API are likely to change in the future.
465
466 */
467 //@{
468 //--------------------------------------------------------------------------------------------------------------------------------------------------------
469 /** Adjoin the canvas to the side of the current canvas.
470
471 @warning This function is experimental! Functionality and API are likely to change in the future.
472
473 @param theCanvas The canvas to adjoin. */
474 void adjoinCanvasRight(const ramCanvasTpl &theCanvas) {
475 intCrdT origNumPixX = getNumPixX();
476 expandCanvas(origNumPixX + theCanvas.getNumPixX(), std::max(getNumPixY(), theCanvas.getNumPixY()));
477 insertCanvas(theCanvas, origNumPixX);
478 }
479 //--------------------------------------------------------------------------------------------------------------------------------------------------------
480 /** Adjoin the canvas to the side of the current canvas.
481
482 @warning This function is experimental! Functionality and API are likely to change in the future.
483
484 @param theCanvas The canvas to adjoin. */
485 void adjoinCanvasLeft(const ramCanvasTpl &theCanvas) {
486 intCrdT origNumPixX = getNumPixX();
487 expandCanvas(origNumPixX + theCanvas.getNumPixX(), std::max(getNumPixY(), theCanvas.getNumPixY()), origNumPixX);
488 insertCanvas(theCanvas);
489 }
490 //--------------------------------------------------------------------------------------------------------------------------------------------------------
491 /** Adjoin the canvas to the side of the current canvas.
492
493 @warning This function is experimental! Functionality and API are likely to change in the future.
494
495 @param theCanvas The canvas to adjoin. */
496 void adjoinCanvasBottom(const ramCanvasTpl &theCanvas) {
497 intCrdT origNumPixY = getNumPixY();
498 expandCanvas(std::max(getNumPixX(), theCanvas.getNumPixX()), origNumPixY + theCanvas.getNumPixY(), 0, origNumPixY);
499 insertCanvas(theCanvas, 0, 0);
500 }
501 //--------------------------------------------------------------------------------------------------------------------------------------------------------
502 /** Adjoin the canvas to the side of the current canvas.
503
504 @warning This function is experimental! Functionality and API are likely to change in the future.
505
506 @param theCanvas The canvas to adjoin. */
507 void adjoinCanvasTop(const ramCanvasTpl &theCanvas) {
508 intCrdT origNumPixY = getNumPixY();
509 expandCanvas(std::max(getNumPixX(), theCanvas.getNumPixX()), origNumPixY + theCanvas.getNumPixY());
510 insertCanvas(theCanvas, 0, origNumPixY);
511 }
512 //--------------------------------------------------------------------------------------------------------------------------------------------------------
513 /** Draw the given canvas at the indicated point.
514
515 @warning This function is experimental! Functionality and API are likely to change in the future.
516
517 @param theCanvas The canvas to draw on the current canvas.
518 @param x1 X coordinate at which to place the canvas.
519 @param y1 Y coordinate at which to place the canvas. */
520 void insertCanvas(const ramCanvasTpl &theCanvas, intCrdT x1 = 0, intCrdT y1 = 0) {
521 for(intCrdT y=0; y<theCanvas.getNumPixY(); y++)
522 for(intCrdT x=0; x<theCanvas.getNumPixX(); x++)
523 drawPoint(x1+x, y1+y, theCanvas.getPxColorRefNC(x, y));
524 }
525 //@}
526
527 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
528 /** @name Canvas resize and crop */
529 //@{
530 //--------------------------------------------------------------------------------------------------------------------------------------------------------
531 /** Resize the canvas to the given size.
532 Contents of new canvas may be random data. Not guarnteed to reallocate the canvas.
533 @param new_numPixX_p The width of the new canvas
534 @param new_numPixY_p The height of the new canvas */
535 void resizeCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p);
536 //--------------------------------------------------------------------------------------------------------------------------------------------------------
537 /** Expand the current canvas.
538 The current image will appear within the new canvas at the specified location. All pixels not set by the previous image
539 will be set to the given color.
540 @param new_numPixX_p The width of the new canvas
541 @param new_numPixY_p The height of the new canvas
542 @param x1 Coord at which the left of the old image will appear in the new image
543 @param y1 Coord at which the top of the old image will appear in the new image
544 @param color Color to use for the background of the new image. */
545 void expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1 = 0, intCrdT y1 = 0, colorArgType color = colorT(colorT::minChanVal));
546 //--------------------------------------------------------------------------------------------------------------------------------------------------------
547 /** This function will crop the canvas to the given rectangular region.
548 @param x1 Left, or right, edge of region to keep.
549 @param x2 Right, or left, edge of region to keep.
550 @param y1 Left, or right, edge of region to keep.
551 @param y2 Right, or left, edge of region to keep. */
552 void cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2);
553 //@}
554
555 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
556 /** @name Coordinate System Manipulation */
557 //@{
558 /** Change the real coordinate system associated with a canvas.
559 It updates all internal parameters are required.
560 @param minRealX_p Minimum real x coordinate value
561 @param maxRealX_p Maximum real x coordinate value
562 @param minRealY_p Minimum real y coordinate value
563 @param maxRealY_p Maximum real y coordinate value */
564 void newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p);
565 //@}
566
567 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
568 /** @name Canvas comparison */
569 //@{
570 //--------------------------------------------------------------------------------------------------------------------------------------------------------
571 /** Return true if given canvas and current canvas are the same size. */
572 inline bool isSameSize(ramCanvasTpl const & inRC) const {
573 if ((numPixY == inRC.getNumPixY()) && (numPixX == inRC.getNumPixX()))
574 return true;
575 else
576 return false;
577 }
578 //--------------------------------------------------------------------------------------------------------------------------------------------------------
579 /** Return true if given canvas and current canvas are *NOT* the same size. */
580 inline bool isNotSameSize(ramCanvasTpl const & inRC) const {
581 if ((numPixY == inRC.getNumPixY()) && (numPixX == inRC.getNumPixX()))
582 return false;
583 else
584 return true;
585 }
586 //--------------------------------------------------------------------------------------------------------------------------------------------------------
587 /** Return true if corresponding pixels in each canvas are "close" as defined by colorTpl::isClose(). */
588 inline bool isClose(ramCanvasTpl const & inRC, colorChanType epsilon) const {
589 if (isNotSameSize(inRC))
590 return false;
591 for(intCrdT y=0; y<numPixY; y++)
592 for(intCrdT x=0; x<numPixX; x++)
593 if ( !(getPxColorRefNC(x, y).isClose(inRC.getPxColorRefNC(x, y), epsilon)))
594 return false;
595 return true;
596 }
597 //--------------------------------------------------------------------------------------------------------------------------------------------------------
598 /** Return true if corresponding pixels in each canvas are "equal" as defined by colorTpl::isEqual(). */
599 inline bool isEqual(ramCanvasTpl const & inRC) const {
600 if (isNotSameSize(inRC))
601 return false;
602 for(intCrdT y=0; y<numPixY; y++)
603 for(intCrdT x=0; x<numPixX; x++)
604 if ( !(getPxColorRefNC(x, y).isEqual(inRC.getPxColorRefNC(x, y))))
605 return false;
606 return true;
607 }
608 //@}
609
610 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
611 /** @name Canvas Rotation and Reflection. */
612 //@{
613 //--------------------------------------------------------------------------------------------------------------------------------------------------------
614 /** Loss-less 90 degree clockwise rotation of the canvas about the center.
615 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
616 "in place", so enough memory is required to duplicate the canvas. */
618 //--------------------------------------------------------------------------------------------------------------------------------------------------------
619 /** Loss-less 90 degree counter clockwise rotation of the canvas about the center.
620 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
621 place", so enough memory is required to duplicate the canvas. */
623 //--------------------------------------------------------------------------------------------------------------------------------------------------------
624 /** Loss-less 180 degree rotation of the canvas about the center.
625 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
626 duplicate the canvas. */
627 void rotate180();
628 //--------------------------------------------------------------------------------------------------------------------------------------------------------
629 /** Loss-less, horizontal flip of the canvas about the center.
630 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. */
631 void flipHorz();
632 //--------------------------------------------------------------------------------------------------------------------------------------------------------
633 /** Loss-less, vertical flip of the canvas about the center.
634 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. */
635 void flipVert();
636 //--------------------------------------------------------------------------------------------------------------------------------------------------------
637 /** Loss-less, vertical flip of the canvas about the center.
638 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.
639 The transformation is not done "in place", so enough memory is required to duplicate the canvas. */
641 //@}
642
643 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
644 /** @name Canvas Scaling. */
645 //@{
646 //--------------------------------------------------------------------------------------------------------------------------------------------------------
647 /** Scale up the image using proximal interpolation.
648 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
649 histograms stay accurate. The algorithm is very fast as it is very simple.
650 @param xfactor The factor to scale up to -- must be a positive integer. */
651 void scaleUpProximal(int xfactor);
652 //--------------------------------------------------------------------------------------------------------------------------------------------------------
653 /** Scale down using only the upper left pixel from each block.
654 This will tend to highlight horizontal and vertical detail and generally sharpen up the image. Much data is lost with this sort of scaling
655 operation.
656 @param xfactor The factor to scale up to -- must be a positive integer. */
657 void scaleDown1pt(int xfactor);
658 //--------------------------------------------------------------------------------------------------------------------------------------------------------
659 /** Scale down using only the pixel with maximum luminosity in each block.
660 Much like scaleDown1pt(), this will sharpen up a scaled image, but it will also tend to brighten up the image as well.
661 @param xfactor The factor to scale up to -- must be a positive integer. */
662 void scaleDownMax(int xfactor);
663 //--------------------------------------------------------------------------------------------------------------------------------------------------------
664 /** Scale down using the mean pixel value from each block.
665 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
666 pixel. This algorithm tends to "fuzz-up" the result -- frequently used for super-sampling.
667 @param xfactor The factor to scale down to -- must be a positive integer. */
668 void scaleDownMean(int xfactor);
669 //@}
670
671 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
672 /** @name Geometric transformations (Reverse Mapping)
673
674 @warning These functions are experimental! Functionality and API are likely to change in the future.
675 */
676 //@{
677 //--------------------------------------------------------------------------------------------------------------------------------------------------------
678 /** Geometric Transform via Radial Polynomial implemented with Reverse Mapping.
679
680 @warning This function is experimental! Functionality and API are likely to change in the future.
681
682 @param RPoly RPoly is a vector listing the coefficients of a univariate polynomial in lexicographical order --
683 i.e. RPoly[0] is the coefficients on the highest power term.
684 @param rScale Scale to apply before the transformation to the *radius*.
685 @param Xo X coordinate for origin translation -- applied before RPoly and reversed after RPoly & scale.
686 @param Yo Y coordinate for origin translation -- applied before RPoly and reversed after RPoly & scale.
687 @param oScale Scale to apply after RPoly and before reverse translation.
688 @param errorColor The color to use for pixels with no valid mapping.
689 @param interpMethod Eventually this will be the interpolation method used. */
690 ramCanvasTpl geomTfrmRevRPoly(std::vector<double> const& RPoly,
691 double rScale,
692 double Xo,
693 double Yo,
694 double oScale,
695 colorArgType errorColor = colorCornerEnum::GREEN,
696 interpolationType interpMethod = interpolationType::BILINEAR);
697 //--------------------------------------------------------------------------------------------------------------------------------------------------------
698 /** Geometric Transform via bivariate polynomial implemented with Reverse Mapping.
699
700 @warning This function is experimental! Functionality and API are likely to change in the future.
701
702 @param BiPolyX Coefficients for a bivariate polynomial in lexicographical order -- used to map x coordinates.
703 @param BiPolyY Coefficients for a bivariate polynomial in lexicographical order -- used to map y coordinates.
704 @param Xo X coordinate for origin translation -- applied before BiPoly*and reversed after BiPoly*& scale.
705 @param Yo Y coordinate for origin translation -- applied before BiPoly*and reversed after BiPoly*& scale.
706 @param oScale Scale to apply after BiPoly*and before reverse translation.
707 @param errorColor The color to use for pixels with no valid mapping.
708 @param interpMethod Eventually this will be the interpolation method used. */
709 ramCanvasTpl geomTfrmRevBiPoly(std::vector<double> const& BiPolyX,
710 std::vector<double> const& BiPolyY,
711 double Xo,
712 double Yo,
713 double oScale,
714 colorArgType errorColor = colorCornerEnum::GREEN,
715 interpolationType interpMethod = interpolationType::BILINEAR);
716 //--------------------------------------------------------------------------------------------------------------------------------------------------------
717 /** Homogenious Affine Geometric Transform implemented with Reverse Mapping.
718
719 @warning This function is experimental! Functionality and API are likely to change in the future.
720
721 @verbatim
722 [1 0 T_x] [S_x 0 0] [cA sA 0] [x_in] [x_out]
723 [0 1 T_y] [0 S_y 0] [-SA cA 0] T * [y_in] => [y_out]
724 [0 0 1 ] [0 0 1] [0 0 1] [1 ] [1 ]
725 @endverbatim
726 @param HAMatrix Homogeneous affine transform matrix -- 9 elements interpreted as a row major order 3x3 matrix.
727 @param Xo X coordinate for origin translation -- applied before HAMatrixand reversed after HAMatrix& scale.
728 @param Yo Y coordinate for origin translation -- applied before HAMatrixand reversed after HAMatrix& scale.
729 @param oScale Scale to apply after HAMatrixand before reverse translation.
730 @param errorColor The color to use for pixels with no valid mapping.
731 @param interpMethod Eventually this will be the interpolation method used. */
732 ramCanvasTpl geomTfrmRevAff(std::vector<double> const& HAMatrix,
733 double Xo,
734 double Yo,
735 double oScale,
736 colorArgType errorColor = colorCornerEnum::GREEN,
737 interpolationType interpMethod = interpolationType::BILINEAR);
738 //--------------------------------------------------------------------------------------------------------------------------------------------------------
739 /** Geometric Transform via provided mapping function implemented with Reverse Mapping.
740
741 @warning This function is experimental! Functionality and API are likely to change in the future.
742
743 @param f The coordinate transformation function
744 @param Xo X coordinate for origin translation -- applied before f and reversed after f & scale.
745 @param Yo Y coordinate for origin translation -- applied before f and reversed after f & scale.
746 @param oScale Scale to apply after f and before reverse translation.
747 @param errorColor The color to use for pixels with no valid mapping.
748 @param interpMethod Eventually this will be the interpolation method used. */
750 double Xo,
751 double Yo,
752 double oScale,
753 colorArgType errorColor = colorCornerEnum::GREEN,
754 interpolationType interpMethod = interpolationType::BILINEAR);
755 //@}
756
757 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
758 /** @name Apply Convolution */
759 //@{
760 //--------------------------------------------------------------------------------------------------------------------------------------------------------
761 /** Apply a convolution filter.
762 The implementation for this method is quite naive and super slow! Frankly, this kind of functionality is beyond the scope of this library; however,
763 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
764 canvas are considered black.
765 @param kernel The convolution kernel. Must be of length kWide*kTall.
766 @param kWide The width of the kernel. Must be odd.
767 @param kTall The height of the kernel. Must be odd.
768 @param divisor Used to normalize dot product at each step. i.e. one might say the kernel for the convolution is really kernel/divisor. */
769 void convolution(double *kernel, int kWide, int kTall, double divisor);
770 void convolution(double *kernel, int kSize, double divisor);
771 void convolution(double *kernel, int kSize);
772 //@}
773
774 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
775 /** @name Compute Convolution Kernels */
776 //@{
777 //--------------------------------------------------------------------------------------------------------------------------------------------------------
778 /** Compute a Gaussian convolution kernel (use with divisor==1.0).
779 @param kernel Pointer to space for the convolution kernel. Must have at least space for kSize*kSize doubles
780 @param kSize The width and height of the kernel. Must be odd.
781 @param sd The standard deviation. */
782 void computeConvolutionMatrixGausian(double *kernel, int kSize, double sd);
783 //--------------------------------------------------------------------------------------------------------------------------------------------------------
784 /** Compute a box blur convolution kernel (use with divisor==1.0).
785 @param kernel Pointer to space for the convolution kernel. Must have at least space for kSize*kSize doubles
786 @param kSize The width and height of the kernel. Must be odd. */
787 void computeConvolutionMatrixBox(double *kernel, int kSize);
788 //@}
789
790 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
791 /** @name Iterators */
792 //@{
793 colorT *begin() { return pixels; }
794 colorT *end() { return pixelsE; }
795 //@}
796
797 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
798 /** @name Functional Homogeneous Pixel Transformations (point operators) */
799 //@{
800 //--------------------------------------------------------------------------------------------------------------------------------------------------------
801 /** Apply a homogeneous pixel transformation.
802 Homogeneous pixel transformations don't vary based upon the coordinates of the pixel in question, but depend only upon the value of the pixel.
803 Thus, a homogeneous pixel transformation can be considered as a pixel function applied to each pixel in an image. Many standard pixel functions are
804 defined within the colorT object. The ramCanvasTpl object must then only apply the methods available within each colorT class to support most of
805 the standard homogeneous pixel transformations. Additionally, new functions are automatically available to the ramCanvasTpl (both in the colorT
806 class and new functions from other sources). */
807 void applyHomoPixTfrm(colorT& (colorT::*HPT)());
808 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double), double);
809 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double, double);
810 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double, double, double);
811 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double), double, double, double, double);
812 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double), double, double, double, double, double);
813 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double), double, double, double, double, double, double);
814 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int), int);
815 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int, int);
816 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int, int, int);
817 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int, int, int, int);
818 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT), colorT);
819 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT, colorT);
820 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT, colorT, colorT);
821 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT, colorT, colorT, colorT);
822 //@}
823
824 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
825 /** @name Functional Homogeneous Pixel Transformations (point operators) */
826 //@{
827 //--------------------------------------------------------------------------------------------------------------------------------------------------------
828 /** Apply a a function to a each pixel via refrence. */
829 void applyPixelRefFun(colorT::cr2voidType f);
830 //@}
831
832 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
833 /** @name Predefined Homogeneous Pixel Transformations (point operators) */
834 //@{
835 //--------------------------------------------------------------------------------------------------------------------------------------------------------
836 /** Computes a linear grey level scale homogeneous pixel transformation.
837 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
838 assumed by any pixel color component. This function is sometimes called "auto contrast adjust" or "linear auto contrast adjust". */
840 //--------------------------------------------------------------------------------------------------------------------------------------------------------
841 /** Computes a, possibly different, linear grey level scale homogeneous pixel transformation on each channel of the image.
842 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.
843 i.e. this is the same as applying autoHistStrech independently to each channel.*/
845 //@}
846
847 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
848 /** @name Canvas Combination Functions */
849 //@{
850 //--------------------------------------------------------------------------------------------------------------------------------------------------------
851 /** This function takes a ramCanvasTpl and combines it with the current ramCanvasTpl using the provided binary operator.
852 @param HPT Pointer to a binary operator.
853 @param theCanvas This is the ramCanvasTpl to combine with.
854 @param trgX Final X coordinate for the left of the combined region. Default: 0
855 @param trgY Final Y coordinate for the top of the combined region. Default: 0
856 @param srcX Left edge of the region to combine with. Default: 0
857 @param srcY Top edge of the region to combine with. Default: 0
858 @param wide Width of the region to combine with. Default: -1 (indicates to edge of canvas)
859 @param tall Height of the region to combine with. Default: -1 (indicates to edge of canvas) */
860 void combineRamCanvasBinOp(colorT& (colorT::*HPT)(colorT),
861 const ramCanvasTpl &theCanvas,
862 intCrdT trgX = 0, intCrdT trgY = 0,
863 intCrdT wide = -1, intCrdT tall = -1,
864 intCrdT srcX = 0, intCrdT srcY = 0);
865 //@}
866
867 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
868 /** @name Statistical Canvas Combination Functions (useful for CCD imaging) */
869 //@{
870 //--------------------------------------------------------------------------------------------------------------------------------------------------------
871 /** Take a list of ramCanvasTpl objects and combine them with the current ramCanvasTpl using mean.
872 @param theCanvasList This is the array of ramCanvasTpl's to combine with.
873 @param N The number of canvas objects. */
874 void combineRamCanvasMean(ramCanvasTpl *theCanvasList, const int N);
875 //@}
876
877 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
878 /** @name Canvas Clearing Methods */
879 //@{
880 //--------------------------------------------------------------------------------------------------------------------------------------------------------
881 /** Clear the canvas to black. Faster than clrCanvas(). */
883 //--------------------------------------------------------------------------------------------------------------------------------------------------------
884 /** Clear the canvas to black. Faster than clrCanvas(). */
886 //--------------------------------------------------------------------------------------------------------------------------------------------------------
887 /** Set the given channel to the minimum value. */
888 void clrCanvasChannelToMin(int chan);
889 //--------------------------------------------------------------------------------------------------------------------------------------------------------
890 /** Set the given channel to the maximum value. */
891 void clrCanvasChannelToMax(int chan);
892 //--------------------------------------------------------------------------------------------------------------------------------------------------------
893 /** Clear the canvas. */
894 void clrCanvas();
895 //--------------------------------------------------------------------------------------------------------------------------------------------------------
896 /** @overload */
898 //@}
899
900 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
901 /** @name Default Point Methods */
902 //@{
903 //--------------------------------------------------------------------------------------------------------------------------------------------------------
904 /** Set the current default point to the given coordinates.
905 @param x The x coordinate of the point to move to.
906 @param y The y coordinate of the point to move to. */
907 inline void moveTo(intCrdT x, intCrdT y) { dfltX = x; dfltY = y; }
908 inline void moveTo(fltCrdT x, fltCrdT y) { moveTo(real2intX(x), real2intY(y)); }
909 inline void moveTo(pointIntType thePoint) { moveTo(thePoint.x, thePoint.y); }
910 inline void moveTo(pointFltType thePoint) { moveTo(real2intX(thePoint.x), real2intY(thePoint.y)); }
911 //@}
912
913 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
914 /** @name Default Color Methods */
915 //@{
916 //--------------------------------------------------------------------------------------------------------------------------------------------------------
917 /** Set the default color */
918 inline void setDfltColor(colorArgType color) { dfltColor = color; }
919 inline void setDfltColor(std::string cornerColor) { dfltColor.setToCorner(cornerColor); }
920 inline void setDfltColor(const char* cornerColor) { dfltColor.setToCorner(std::string(cornerColor)); }
921 inline void setDfltColor(colorChanType r, colorChanType g, colorChanType b) { dfltColor.setChansRGB(r, g, b); }
922 //@}
923
924 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
925 /** @name Point drawing functions */
926 //@{
927 //--------------------------------------------------------------------------------------------------------------------------------------------------------
928 /** Draw a point at the specified coordinates with the specified color.
929 Overloaded versions exist with various arguments.
930 @param x The x coordinate of the point
931 @param y The y coordinate of the point
932 @param color The color to draw the point */
933 inline void drawPoint(intCrdT x, intCrdT y, colorArgType color) {
934 if(isOnCanvas(x, y))
935 drawPointNC(x, y, color);
936 }
938 inline void drawPoint(colorArgType color) { drawPoint(dfltX, dfltY, color); }
939 inline void drawPoint(intCrdT x, intCrdT y) { drawPoint(x, y, dfltColor); }
940 inline void drawPoint(fltCrdT x, fltCrdT y) { drawPoint(x, y, dfltColor); }
941 inline void drawPoint(fltCrdT x, fltCrdT y, colorArgType color) { drawPoint(real2intX(x), real2intY(y), color); }
942 inline void drawPoint(pointIntType thePoint, colorArgType color) { drawPoint(thePoint.x, thePoint.y, color); }
943 inline void drawPoint(pointIntType thePoint) { drawPoint(thePoint.x, thePoint.y, dfltColor); }
944 inline void drawPoint(pointFltType thePoint) { drawPoint(real2intX(thePoint.x), real2intY(thePoint.y), dfltColor); }
945 inline void drawPoint(pointFltType thePoint, colorArgType color) { drawPoint(real2intX(thePoint.x), real2intY(thePoint.y), color); }
946 //@}
947
948 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
949 /** @name Single pixel transformation functions.
950 These functions provide a simple and direct way to modify a pixel by passing a frefrence to a callable (usually a lambda). This can be used to
951 mimic the functality of drawModeType by simply passing the approprate color transformation member
952 for 2D image histograms or the solutions to differential equations -- both applications being very common when working with fractals and dynamical
953 systems. While the same result can be obtained with tformPixel() with a lambda like ~[i](auto& c) { c.tfrmAdd(i); }~, these routines can be
954 significantly faster for some compilers.
955
956 */
957 //@{
958 //--------------------------------------------------------------------------------------------------------------------------------------------------------
959 /** Transform the pixel at the specified coordinates.
960 Overloaded versions exist with various arguments.
961 @param x The x coordinate of the pixel
962 @param y The y coordinate of the pixel
963 @param transform The color to draw the pixel */
964 inline void tformPixel(intCrdT x, intCrdT y, colorType::cr2voidType tform) {
965 if(isOnCanvas(x, y))
966 tform(getPxColorRefNC(x, y));
967 }
968 inline void tformPixel(fltCrdT x, fltCrdT y, colorType::cr2voidType tform) { tformPixel(real2intX(x), real2intY(y), tform); }
969 inline void tformPixel(pointIntType thePoint, colorType::cr2voidType tform) { tformPixel(thePoint.x, thePoint.y, tform); }
970 inline void tformPixel(pointFltType thePoint, colorType::cr2voidType tform) { tformPixel(real2intX(thePoint.x), real2intY(thePoint.y), tform); }
971 //@}
972
973 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
974 /** @name Increment a channel value for a pixel.
975 These functions provide a simple and direct way to increment a single channel for a particular pixel. Typical use cases are to accumulate values
976 for 2D image histograms or the solutions to differential equations -- both applications being very common when working with fractals and dynamical
977 systems. While the same result can be obtained with tformPixel() with a lambda like ~[i](auto& c) { c.tfrmAdd(i); }~, these routines can be
978 significantly faster for some compilers.
979 */
980 //@{
981 //--------------------------------------------------------------------------------------------------------------------------------------------------------
982 /** Increment the specified color channel of the pixel at the given coordinates by the specified value.
983 Overloaded versions exist with various arguments.
984 @param x The x coordinate of the point
985 @param y The y coordinate of the point
986 @param v The incriment value */
987 template <int chanNum = 0>
988 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
989 inline void incPxChan(intCrdT x, intCrdT y, colorChanType v = 1) {
990 if(isOnCanvas(x, y))
991 getPxColorRefNC(x, y).tfrmChanIncr(chanNum, v);
992 }
993 //--------------------------------------------------------------------------------------------------------------------------------------------------------
994 template <int chanNum = 0>
995 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
996 inline void incPxChan(fltCrdT x, fltCrdT y, colorChanType v = 1) {
997 intCrdT xi = real2intX(x);
998 intCrdT yi = real2intY(y);
999 incPxChan<chanNum>(xi, yi, v);
1000 }
1001 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1002 template <int chanNum = 0>
1003 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1004 inline void incPxChan(pointIntType thePoint, colorChanType v = 1) { incPxChan<chanNum>(thePoint.x, thePoint.y, v); }
1005 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1006 template <int chanNum = 0>
1007 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1008 inline void incPxChan(pointFltType thePoint, colorChanType v = 1) { incPxChan<chanNum>(thePoint.x, thePoint.y, v); }
1009 //@}
1010
1011 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1012 /** @name Line Drawing Methods */
1013 //@{
1014 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1015 /** Draw a line.
1016 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
1017 current canvas.
1018 @param x1 x coordinate of the first point
1019 @param y1 y coordinate of the first point
1020 @param x2 x coordinate of the second point
1021 @param y2 y coordinate of the second point
1022 @param color The color to use
1023
1024 @par Performance Note
1025 This function will perform better if (x1,y2) and (x2,y2) are in the clip region. Further x1<x2 will save several steps in
1026 the algorithm.
1027
1028 @par Algorithm Notes
1029 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
1030 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
1031 for positive slope lines and for negative slope lines.
1032
1033 The algorithms used to draw lines in the last four cases are related to the classic algorithm presented by Bresenham in 1965 and the
1034 extensions to Bresenham's algorithm given by Pitteway in 1967 and Van Aken in 1984. The basic algorithm described by Bresenham, Pitteway, and Van
1035 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
1036 obvious extensions to the midpoint algorithm. Each case is customized and optimized for the given slope class.
1037
1038 The clipping algorithm used for the last slope classes is similar in spirit to the Cohen-Sutherland Line-Clipping algorithm, but is optimized
1039 for each slope class. Several pre-checks are made in order to avoid the slope computations in the Cohen-Sutherland algorithm -- in fact intersections
1040 are only computed if absolutely required. Note that the only floating point computations in this function are the intersection computations, and they
1041 will be avoided completely if the given line need not be clipped.*/
1042 void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1043 inline void drawLine(pointFltType point1) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), dfltColor); }
1044 inline void drawLine(pointFltType point1, colorArgType color) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), color); }
1045 inline void drawLine(pointIntType point1) { drawLine( dfltX, dfltY, point1.x, point1.y, dfltColor); }
1046 inline void drawLine(pointIntType point1, colorArgType color) { drawLine( dfltX, dfltY, point1.x, point1.y, color); }
1047 inline void drawLine(pointFltType point1, pointFltType point2) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1048 inline void drawLine(pointFltType point1, pointFltType point2, colorArgType color) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1049 inline void drawLine(pointIntType point1, pointIntType point2) { drawLine( point1.x, point1.y, point2.x, point2.y, dfltColor); }
1050 inline void drawLine(pointIntType point1, pointIntType point2, colorArgType color) { drawLine( point1.x, point1.y, point2.x, point2.y, color); }
1051 inline void drawLine(intCrdT x, intCrdT y) { drawLine( dfltX, dfltY, x, y, dfltColor); }
1052 inline void drawLine(fltCrdT x, fltCrdT y) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), dfltColor); }
1053 inline void drawLine(intCrdT x, intCrdT y, colorArgType color) { drawLine( dfltX, dfltY, x, y, color); }
1054 inline void drawLine(fltCrdT x, fltCrdT y, colorArgType color) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), color); }
1055 inline void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
1056 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
1057 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawLine( real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1058 //@}
1059
1060 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1061 /** @name Unfilled Triangle Drawing Methods */
1062 //@{
1063 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1064 /** Draw an un-filled triangle
1065 @bug Some pixels may be drawn more than once.
1066 @param x1 The x coordinate of the first point
1067 @param y1 The y coordinate of the first point
1068 @param x2 The x coordinate of the second point
1069 @param y2 The y coordinate of the second point
1070 @param x3 The x coordinate of the third point
1071 @param y3 The y coordinate of the third point
1072 @param color The color to use for the triangle */
1073 void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1074 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); }
1075 inline void drawTriangle(pointFltType *thePoints) { 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), dfltColor); }
1078 inline void drawTriangle(pointFltType *thePoints, colorArgType color) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1079 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1080 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1081 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); }
1082 inline void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1083 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1084 real2intX(point2.x), real2intY(point2.y),
1085 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1086 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1087 real2intX(point2.x), real2intY(point2.y),
1088 real2intX(point3.x), real2intY(point3.y), color); }
1089 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); }
1090 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); }
1091 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); }
1092 inline void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1093 //@}
1094
1095 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1096 /** @name Filled Triangle Drawing Methods */
1097 //@{
1098 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1099 /** Draw a triangle filled with a solid color using a nicely optimized, horizontal scan conversion algorithm.
1100 @bug Triangles not entirely on the canvas are not rendered.
1101 @bug Not thread safe.
1102 @param x1 The x coordinate of the first point
1103 @param y1 The y coordinate of the first point
1104 @param x2 The x coordinate of the second point
1105 @param y2 The y coordinate of the second point
1106 @param x3 The x coordinate of the third point
1107 @param y3 The y coordinate of the third point
1108 @param color The color to use for the triangle */
1109 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1110 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); }
1111 inline void drawFillTriangle(pointFltType *thePoints) { 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), dfltColor); }
1114 inline void drawFillTriangle(pointFltType *thePoints, colorArgType color) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1115 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1116 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1117 inline void drawFillTriangle(pointIntType *thePoints) { drawFillTriangle(thePoints[0].x, thePoints[0].y,
1118 thePoints[1].x, thePoints[1].y,
1119 thePoints[2].x, thePoints[2].y, dfltColor); }
1120 inline void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawFillTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1121 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1122 real2intX(point2.x), real2intY(point2.y),
1123 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1124 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1125 real2intX(point2.x), real2intY(point2.y),
1126 real2intX(point3.x), real2intY(point3.y), color); }
1127 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); }
1128 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); }
1129 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); }
1130 inline void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawFillTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1131 //@}
1132
1133 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1134 /** @name Shaded Triangle Drawing Methods */
1135 //@{
1136 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1137 /** Draw a filled triangle using barycentric color interpolation.
1138 @bug Triangles not entirely on the canvas are not rendered.
1139 @bug Degenerate trainagles are not rendered
1140 @bug Painfully slow
1141 @param x1 The x coordinate of the first point
1142 @param y1 The y coordinate of the first point
1143 @param x2 The x coordinate of the second point
1144 @param y2 The y coordinate of the second point
1145 @param x3 The x coordinate of the third point
1146 @param y3 The y coordinate of the third point
1147 @param color1 The color of the first point (x1, y1)
1148 @param color2 The color of the second point (x2, y2)
1149 @param color3 The color of the third point (x3, y3) */
1150 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color1, colorArgType color2, colorArgType color3);
1151 //@}
1152
1153 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1154 /** @name Unfilled Rectangle Drawing Functions */
1155 //@{
1156 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1157 /** Draw an unfilled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1158 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
1159 the bounds of the canvas using the specified color.
1160 @param x1 The x coordinate of first corner
1161 @param y1 The y coordinate of first corner
1162 @param x2 The x coordinate of second corner
1163 @param y2 The y coordinate of second corner
1164 @param color The color to use */
1165 void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1166 inline void drawRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1167 inline void drawRectangle(pointIntType point1, pointIntType point2) { drawRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1168 inline void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1169 inline void drawRectangle(pointFltType point1, pointFltType point2) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1170 inline void drawRectangle(pointIntType *thePoints, colorArgType color) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1171 inline void drawRectangle(pointFltType *thePoints) { drawRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1172 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); }
1173 inline void drawRectangle(pointIntType *thePoints) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1174 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1175 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1176 inline void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawRectangle(x1, y1, x2, y2, dfltColor); }
1177 //@}
1178
1179 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1180 /** @name Filled Rectangle Drawing Methods */
1181 //@{
1182 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1183 /** Draw a filled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1184 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
1185 the bounds of the canvas using the specified color.
1186 @param x1 The x coordinate of first corner
1187 @param y1 The y coordinate of first corner
1188 @param x2 The x coordinate of second corner
1189 @param y2 The y coordinate of second corner
1190 @param color The color to use */
1191 void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1192 inline void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1193 inline void drawFillRectangle(pointIntType point1, pointIntType point2) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1194 inline void drawFillRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1195 inline void drawFillRectangle(pointFltType point1, pointFltType point2) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1196 inline void drawFillRectangle(pointIntType *thePoints, colorArgType color) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1197 inline void drawFillRectangle(pointFltType *thePoints) { drawFillRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1198 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); }
1199 inline void drawFillRectangle(pointIntType *thePoints) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1200 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1201 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1202 inline void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawFillRectangle(x1, y1, x2, y2, dfltColor); }
1203 //@}
1204
1205 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1206 /** @name Unfilled Circle Drawing Methods */
1207 //@{
1208 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1209 /** Draw an un-filled circle.
1210 The algorithm used is based upon the one presented in "A Linear Algorithm for Incremental Digital Display of Circular Arcs" published in the
1211 Communications of the AMC in Feb 1977 and written by J.E. Bresenham. Bresenham's algorithm has been significantly improved by using only integer
1212 arithmetic and adding second order differences to the computation -- much the way the line drawing algorithm works in this package. The algorithm
1213 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
1214 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.
1215 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
1216 optimized.
1217 @bug Draws everyting even if it's off the canvas.
1218 @param centerX The x coordinate of the center
1219 @param centerY The y coordinate of the center
1220 @param radiusX The radius of the circle
1221 @param color The color to draw the circle with */
1222 void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1223 inline void drawCircle(intCrdT radiusX) { drawCircle(dfltX, dfltY, radiusX, dfltColor); }
1224 inline void drawCircle(fltCrdT radiusX) { drawCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1225 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1226 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1227 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX) { drawCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1228 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1229 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1230 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1231 inline void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawCircle(centerX, centerY, radiusX, dfltColor); }
1232 //@}
1233
1234 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1235 /** @name Filled Circle Drawing Methods */
1236 //@{
1237 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1238 /** Draw an un-filled circle.
1239 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
1240 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
1241 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
1242 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
1243 X axis -- i.e. the radius of the drawn circle will be measured horizontally. This function is well optimized.
1244 @bug Draws everyting even if it's off the canvas.
1245 @param centerX The x coordinate of the center
1246 @param centerY The y coordinate of the center
1247 @param radiusX The radius of the circle
1248 @param color The color to draw the circle with */
1249 void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1250 inline void drawFillCircle(fltCrdT radiusX) { drawFillCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1251 inline void drawFillCircle(intCrdT radiusX) { drawFillCircle(dfltX, dfltY, radiusX, dfltColor); }
1252 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1253 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1254 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1255 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1256 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1257 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1258 inline void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawFillCircle(centerX, centerY, radiusX, dfltColor); }
1259 //@}
1260
1261 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1262 /** @name Piece-Wise Linear Curve Drawing Methods */
1263 //@{
1264 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1265 /** Draw Piece-Wise Linear Curves
1266 @bug Some pixels may be drawn more than once.
1267 */
1268 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y, colorArgType color);
1269 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y);
1270 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y, colorArgType color);
1271 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y);
1272 void drawPLCurve(int numPoints, pointIntType *thePoints, colorArgType color);
1273 void drawPLCurve(int numPoints, pointIntType *thePoints);
1274 void drawPLCurve(int numPoints, pointFltType *thePoints, colorArgType color);
1275 void drawPLCurve(int numPoints, pointFltType *thePoints);
1276 //@}
1277
1278 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1279 /** @name Hershey Glyph Rendering Utility Functions */
1280 //@{
1281 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1282 /** Render a glyph from the Hershey character set.
1283 The glyph is rendered with its origin at the given coordinates. This function is intended to provide only the most basic glyph rendering. For
1284 example, glyphs are rendered with the line drawing functions, and therefore are not anti-aliased.
1285 @param glyphNum The character number of the glyph to render
1286 @param x The x coordinate at which to render the glyph
1287 @param y The x coordinate at which to render the glyph
1288 @param magX The magnification of the glyph in the x direction
1289 @param magY The magnification of the glyph in the y direction
1290 @param aColor The color with which to render the glyph */
1291 void drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor);
1292 void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor) { drawHersheyGlyph(glyphNum, real2intX(x), real2intY(y), magX, magY, aColor); }
1293 //@}
1294
1295 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1296 /** @name ASCII Character Rendering.
1297 What are font rendering functions doing in a raster graphics library? Sometimes I like to put a label on image.*/
1298 //@{
1299 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1300 /** Render a string using Hershey ASCII Fonts.
1301 While the string is rendered with fixed font spacing, the Hershey fonts are not fixed width fonts.
1302 @param aString The string
1303 @param aFont The font to set the default with
1304 @param x The x coordinate at which to render the first glyph
1305 @param y The x coordinate at which to render the first glyph
1306 @param aColor The color with which to render the glyphs
1307 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1308 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1309 void drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc);
1310 void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc) {
1311 drawString(aString, aFont, real2intX(x), real2intY(y), aColor, cex, spc);
1312 }
1313 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1314 /** Renders a filled, bounding box for the given string as rendered via drawString.
1315 @param aString A string to render
1316 @param aFont The font to set the default with
1317 @param x The x coordinate at which to render the first glyph
1318 @param y The x coordinate at which to render the first glyph
1319 @param stringColor The color with which to render the glyphs
1320 @param boxColor The color with which to render the BOX
1321 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1322 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1323 void drawStringBox(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc);
1324 void drawStringBox(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc) {
1325 drawStringBox(aString, aFont, real2intX(x), real2intY(y), stringColor, boxColor, cex, spc);
1326 }
1327 //@}
1328
1329 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1330 /** @name File Reading and Writing Methods */
1331 //@{
1332 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1333 /** Is libTIFF supported -- that is: will the readTIFFfile() method do anything?
1334 Note that readTIFFfile() is the only method that needs libTIFF. In particular, writeTIFFfile() works without libTIFF. */
1336 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1337 /** If the libTIFF library was found at build time, this function will read a TIFF file into current ramCanvas object.
1338
1339 If libTIFF is not supported, then this function returns 32. You can test if this method works via the supportLibTIFF() method.
1340
1341 Notable features:
1342 - Arbitrary TIFF image file types are converted to 24-bit RGB when aRamCanvas is of type ramCanvas3c8b
1343 - Note aRamCanvas must be of type ramCanvas3c8b -- ramCanvas4c8b is not good enough.
1344 - Reasonable conversions are made in other cases.
1345 - if aRamCanvas has fewer channels than the TIFF file, then extra channels in the TIFF file are ignored
1346 - if aRamCanvas has more channels than the TIFF file, then extra channels of aRamCanvas are set to black
1347 - 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)
1348 - Some effort is taken to do the right thing with respect to aRamCanvas axis orientation
1349
1350 @param fileName The file name from which to read data from.
1351 @retval 0 Image file loaded successfully
1352 @retval 1 File open (TIFFOpen) failure
1353 @retval 2 File missing TIFF tag: IMAGEWIDTH
1354 @retval 3 File missing TIFF tag: IMAGELENGTH
1355 @retval 4 File missing TIFF tag: SAMPLESPERPIXEL
1356 @retval 5 File missing TIFF tag: PLANARCONFIG
1357 @retval 6 File missing TIFF tag: PHOTOMETRIC
1358 @retval 7 File missing TIFF tag: BITSPERSAMPLE
1359 @retval 8 File of zero width
1360 @retval 9 File of zero height
1361 @retval 10 Allocation failed (temp image buffer)
1362 @retval 11 Read (TIFFReadRGBAImage) failure
1363 @retval 12 Canvas Allocation failed (insufficient width)
1364 @retval 14 Canvas Allocation failed (insufficient height)
1365 @retval 15 TIFF bps not 8, 16, 32, or 64
1366 @retval 16 Allocation failed (scan line buffer)
1367 @retval 17 Read (TIFFReadScanline) failure
1368 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1369 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1370 @retval 20 File and ramCanvas channel depth differ
1371 @retval 21 File and ramCanvas channel format (int vs float) differ
1372 @retval 22 Planar configuration is invalid (not 1 or 2)
1373 @retval 23 Tiled images are not supported
1374 @retval 24 PHOTOMETRIC_PALETTE not supported
1375 @retval 32 TIFF read support not provided in this compile */
1376 int readTIFFfile(std::string fileName);
1377 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1378 /** Write a TIFF format image file. Respects integer coordinate system orientation.
1379
1380 Why TIFF? TIFF is both broadly supported and flexible enough to represent almost every ramCanvas image type perfectly.
1381
1382 Use Cases (In order of priority)
1383 - Write a bit perfect TIFF representation of ramCanvas images
1384 - Simultaneously convert any ramCanvas into 24-bit truecolor RGB and write the resulting TIFF
1385 - Do all the above while simultaneously applying a homogeneous image filter
1386
1387 Limitations
1388 - Channels must be no more than 64-bits wide
1389 - No more than 2^16-1 channels
1390 - Image width no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1391 - Image height no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1392 - Image row data size (numPixX * colorT::bitsPerChan * colorT::channelCount / 8) must be less than 2^32-1 bytes
1393 - Image data must be less than 2^32-1 bytes
1394
1395 Limitations for bit perfect (toTRU is NULL) files:
1396 - Channels must be uint8_t, uint16_t, uint32_t, uint64_t, float (32-bit), or double (64-bit)
1397
1398 @param fileName The file name to write data to
1399 @param pxFilter An pxFilter object instance
1400 @param markAlpha If an alpha channel is present, then mark it as such in the TIFF file.
1401 @return Status of I/O
1402 @retval 0 Everything seems to have worked
1403 @retval 2 Image channels are too shallow for TIFF format
1404 @retval 3 Image channels are too deep for TIFF format
1405 @retval 4 Image has too few channels for TIFF format
1406 @retval 5 Image has too many channels for TIFF format
1407 @retval 6 Image has too few columns for TIFF format
1408 @retval 7 Image has too many columns for TIFF format
1409 @retval 8 Image has too few rows for TIFF format
1410 @retval 9 Image has too few rows for TIFF format
1411 @retval 10 Image rows are too large (too much data) for TIFF format
1412 @retval 11 Image is too large (too much data) for TIFF format */
1413 template <class rcConT> int writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha = true);
1414 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1415 /** Simplified overload for writeTIFFfile() that only requires the filename. */
1416 int writeTIFFfile(std::string fileName, bool markAlpha = true);
1417 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1418 /** Write a 24-bit (8-bit per channel) RGB, TGA format graphics file. Respects integer coordinate system orientation.
1419
1420 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
1421 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
1422 function to dump out regular RGB images, but I suggest writeTIFFfile() for that.
1423
1424 Note TGA files are 8-bit files, and *_byte functions are used to convert channel values to 8-bit before being written.
1425
1426 @param fileName The file name name to write data to
1427 @return Status of I/O
1428 @retval 0 Everything seems to have worked
1429 @retval 1 File open failure
1430 @retval 6 Image of zero width
1431 @retval 7 Image too wide for TGA format (> 2^16-1)
1432 @retval 8 Image of zero height
1433 @retval 9 Image too tall for TGA format (> 2^16-1) */
1434 int writeTGAfile(std::string fileName);
1435 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1436 /** Read RAW file
1437
1438 @warning This function is experimental! Functionality and API are likely to change in the future.
1439
1440 @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
1441 good fix looks like
1442
1443 @retval 0 Image file loaded successfully
1444 @retval 1 File open failure
1445 @retval 2 NOT USED
1446 @retval 3 NOT USED
1447 @retval 4 NOT USED
1448 @retval 5 NOT USED
1449 @retval 6 NOT USED
1450 @retval 7 NOT USED
1451 @retval 8 File of zero width
1452 @retval 9 File of zero height
1453 @retval 10 NOT USED
1454 @retval 11 Read failure
1455 @retval 12 Canvas Allocation failed (insufficient width)
1456 @retval 14 Canvas Allocation failed (insufficient height)
1457 @retval 15 bps not 8, 16, 32, or 64
1458 @retval 16 NOT USED
1459 @retval 17 NOT USED
1460 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1461 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1462 @retval 20 File and ramCanvas channel depth differ
1463 @retval 21 File and ramCanvas channel format (int vs float) differ
1464 @retval 22 NOT USED
1465 @retval 23 File is signed integer or unsigned float
1466 @retval 24 File is missing MJRRAW magic number
1467 @retval 25 Image data read failure (file may have ended prematurely)
1468 @retval 26 Malformed header
1469 @retval 27 Image is too wide to be supported by ramCanvas
1470 @retval 28 Image is too tall to be supported by ramCanvas
1471 @retval 29 Error reading numbers in header
1472 @retval 32 NOT USED
1473 @retval 33 Image width missing from header
1474 @retval 34 Image height missing from header
1475 @retval 35 Image channel count missing from header
1476 @retval 36 Image channel depth missing from header */
1477 int readRAWfile(std::string fileName);
1478 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1479 /** Write a MJRRAW file. Respects integer coordinate system orientation.
1480
1481 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
1482 data visualization tools -- usually via a feature referred to as a raw importer. ImageMagick, VisIT, ParaView, and ImageJ all can read this type of
1483 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,
1484 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
1485 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.
1486 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
1487 single lower case letter. If a value is a number, then it is expressed as a decimal number in ASCII -- possibly zero padded. While the code in
1488 ramCanvasTpl doesn't make assumptions about the order of the header values, some of the example scripts require them to be in the following order:
1489 x, y, c, b, s, t, & i. The header is followed by the binary image.
1490
1491 Labels:
1492 - x: Number of pixels on X (horizontal axis) expressed as a zero padded, decimal integer
1493 - y: Number of pixels on Y (vertical axis) expressed as a zero padded, decimal integer
1494 - c: Number of channels expressed as a zero padded, decimal integer
1495 - b: Number of bits per channel expressed as a zero padded, decimal integer
1496 - s: Channel signdness (ignored for floating point channels)
1497 - UNS: Unsigned data. DEFAULT VALUE.
1498 - SGN: Signed data
1499 - t: Channel type
1500 - INT: Integral channels. DEFAULT VALUE.
1501 - FLT: Floating point channels
1502 - i: endianness
1503 - BIG: Big endian
1504 - LTL: Little endian
1505 - UNK: Unknown. DEFAULT VALUE. For read we assume file matches system running the code.
1506 - Currently reserved, but unused labels
1507 - p: Pixel format
1508 - MXL: Each pixel of the image is written in sequence. DEFAULT VALUE.
1509 - PLN: Each channel of the *image* is written in sequence.
1510 - BIT: For bit-masks with 8 bits packed in a byte.
1511 - z: Compression
1512 - 000: No compression. DEFAULT VALUE.
1513 - ZLB: Zlib.
1514 - GZP: Gzip.
1515
1516 Two headers that both specify a 256x128 image with 3 unsigned 8-bit integer channels encoded little endian:
1517
1518 MJRRAW
1519 256x128y3c8bUNSsINTtLTLi00000000000000000000000000000000000000000000000000000000000000000000
1520
1521 MJRRAW
1522 0000000000000000256x0000000000000000128y000000000000000000000000003c00000000008bSGNsINTtLTLi
1523
1524 @param fileName The file name name to write data to
1525 @param pxFilter An pxFilter object instance
1526 @retval 0 The write was successful.
1527 @retval 1 Could not open file. */
1528 template <class rcConT> int writeRAWfile(std::string fileName, rcConT pxFilter);
1529 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1530 /** Simplified overload for writeRAWfile() that only requires the filename. */
1531 int writeRAWfile(std::string fileName);
1532 //@}
1533
1534 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1535 /** @name Boolean Clip Test Methods */
1536 //@{
1537 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1538 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1539 @param x The x coordinate of the point to test
1540 @param y The y coordinate of the point to test
1541 @return Returns true if the point would be clipped. */
1542 inline int isCliped(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1543 inline int isCliped(intCrdT x, intCrdT y) const { return ((x < 0) || (y < 0) || (x >= numPixX) || (y >= numPixY)); }
1544 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1545 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1546 @param x The x coordinate of the point to test
1547 @param y The y coordinate of the point to test
1548 @return Returns true if the point would be not be clipped. */
1549 inline int isOnCanvas(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1550 inline int isOnCanvas(intCrdT x, intCrdT y) const { return ((x >= 0) && (y >= 0) && (x < numPixX) && (y < numPixY)); }
1551 //@}
1552
1553 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1554 /** @name Coordinate Conversions. */
1555 //@{
1556 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1557 /** Convert real x coordinate to integral x coordinate
1558 @param x The real x coordinate value to be converted.
1559 @return The integer x coordinate corresponding to the given x coordinate */
1560 intCrdT real2intX(fltCrdT x) const;
1561 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1562 /** Convert real y coordinate to integral y coordinate
1563 @param y The real y coordinate value to be converted.
1564 @return The integer y coordinate corresponding to the given y coordinate */
1565 intCrdT real2intY(fltCrdT y) const;
1566 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1567 /** Convert integral x coordinate to real x coordinate
1568 @param x The integer x coordinate value to be converted.
1569 @return The real x coordinate corresponding to the given x coordinate */
1570 fltCrdT int2realX(intCrdT x);
1571 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1572 /** Convert integral y coordinate to real y coordinate
1573 @param y The integer y coordinate value to be converted.
1574 @return The real y coordinate corresponding to the given y coordinate */
1575 fltCrdT int2realY(intCrdT y);
1576 //@}
1577
1578 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1579 /** @name Coordinate Pair Conversions. */
1580 //@{
1581 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1582 /** Convert real x & y coordinates to integer x & y coordinates
1583 @param x The integer x coordinate value to be converted.
1584 @param y The integer y coordinate value to be converted.
1585 @return The real x & y coordinates corresponding to the given integer x & y coordinates */
1586 inline pointFltType int2real(intCrdT x, intCrdT y) { return point2d(int2realX(x), int2realY(y)); }
1587 /** Convert integer x & y coordinates to real x & y coordinates
1588 @param x The real x coordinate value to be converted.
1589 @param y The real y coordinate value to be converted.
1590 @return The integer x & y coordinates corresponding to the given real x & y coordinates */
1591 inline pointIntType real2int(intCrdT x, intCrdT y) { return point2d(real2intX(x), real2intY(y)); }
1592 //@}
1593
1594 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1595 /** @name Pixel Corner Coordinates.
1596 */
1597 //@{
1598 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1599 /** Given integer x coordinate, produce real x coordinate for one of the pixel's edge.
1600 @param x The integer x coordinate value to be converted.
1601 @param side The integer x coordinate of the corner -- should be 0 (lower) or 1 (upper).
1602 @return The real x & y coordinates corresponding to the requested corner */
1603 inline fltCrdT int2realSideX(intCrdT x, int side) { return int2realX(x)+pixWidX/(side ? static_cast<fltCrdT>(2.0) : static_cast<fltCrdT>(-2.0)); }
1604 /** Given integer y coordinate, produce real y coordinate for one of the pixel's edge.
1605 @param y The integer y coordinate value to be converted.
1606 @param side The integer y coordinate of the corner -- should be 0 (lower) or 1 (upper).
1607 @return The real y coordinates corresponding to the requested side */
1608 inline fltCrdT int2realSideY(intCrdT y, int side) { return int2realY(y)+pixWidY/(side ? static_cast<fltCrdT>(2.0) : static_cast<fltCrdT>(-2.0)); }
1609 /** Given integer x & y coordinates, produce real x & y coordinates for one of the pixel's corners.
1610 @param x The integer x coordinate value to be converted.
1611 @param y The integer y coordinate value to be converted.
1612 @param sideX The integer x coordinate of the corner -- should be 0 (lower) or 1 (upper).
1613 @param sideY The integer y coordinate of the corner -- should be 0 (lower) or 1 (upper).
1614 @return The real x & y coordinates corresponding to the requested corner */
1615 inline pointFltType int2realCorner(intCrdT x, intCrdT y, int sideX, int sideY) {return point2d(int2realSideX(x, sideX), int2realSideY(y, sideY)); }
1616 /** Given integer x & y coordinates and a corner index, produce real x & y coordinates for one of the pixel's corners.
1617 @param x The integer x coordinate value to be converted.
1618 @param y The integer y coordinate value to be converted.
1619 @param cornerIndex Corner index. 0 => (0, 0); 1 => (0, 1); 2 => (1, 0); 3 => (1, 1);
1620 @return The real x & y coordinates corresponding to the requested corner */
1621 inline pointFltType int2realCorner(intCrdT x, intCrdT y, int cornerIndex) { return int2realCorner(x, y, (cornerIndex >> 1), (cornerIndex & 1)); }
1622 //@}
1623
1624 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1625 /** @name Coordinate Delta Conversions. */
1626 //@{
1627 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1628 /** Convert real distance on the x coordinate axis to an integral distance
1629 @param x The real delta x to be converted
1630 @return integer delta x */
1631 inline intCrdT realDelta2intX(fltCrdT x) const { return static_cast<intCrdT>(static_cast<fltCrdT>(x)/pixWidX); }
1632 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1633 /** Convert real distance on the y coordinate axis to an integral distance
1634 @param y The real delta y to be converted
1635 @return integer delta y */
1636 inline intCrdT realDelta2intY(fltCrdT y) const { return static_cast<intCrdT>(static_cast<fltCrdT>(y)/pixWidY); }
1637 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1638 /** Convert integral distance on the x coordinate to a real distance
1639 @param x The real x coordinate value to be converted.
1640 @return The integer x coordinate corresponding to the given x coordinate */
1641 inline fltCrdT intDelta2realX(intCrdT x) const { return static_cast<fltCrdT>(x)*pixWidX; }
1642 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1643 /** Convert integral distance on the y coordinate to a real distance
1644 @param y real y coordinate value to be converted.
1645 @return The integer y coordinate corresponding to the given y coordinate */
1646 inline fltCrdT intDelta2realY(intCrdT y) const { return static_cast<fltCrdT>(y)*pixWidY; }
1647 //@}
1648
1649 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1650 /** @name Orientation of Real Coordinate Systems */
1651 //@{
1652 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1653 /** Get the real X axis orientation
1654 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1656 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1657 /** Set the real X axis orientation
1658 @param orientation The orientation (INVERTED or NATURAL)*/
1659 inline void setRealAxOrientationX(realAxisOrientation orientation) { realAxOrientationX = orientation; }
1660 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1661 /** Get the real Y axis orientation
1662 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1664 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1665 /** Set the real Y axis orientation
1666 @param orientation The orientation (INVERTED or NATURAL) */
1667 inline void setRealAxOrientationY(realAxisOrientation orientation) { realAxOrientationY = orientation; }
1668 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1669 /** Set the real axis orientation to default (NATURAL for both X and Y axes) */
1670 inline void setRealAxisDefaultOrientation() { setRealAxOrientationX(realAxisOrientation::NATURAL); setRealAxOrientationY(realAxisOrientation::NATURAL); }
1671 //@}
1672
1673 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1674 /** @name Drawing Mode */
1675 //@{
1676 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1677 /** Get the current drawing mode.
1678 @return The drawing mode */
1679 inline drawModeType getDrawMode() { return drawMode; }
1680 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1681 /** Set the current drawing mode
1682 NOOP if enableDrawModes is false.
1683 @param newDrawMode The drawing mode */
1684 inline void setDrawMode(drawModeType newDrawMode) { if constexpr (enableDrawModes) drawMode = newDrawMode; }
1685 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1686 /** Set the default draw mode */
1687 inline void setDefaultDrawMode() { setDrawMode(drawModeType::SET); }
1688 //@}
1689
1690 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1691 /** @name Orientation of Integer Coordinate Systems */
1692 //@{
1693 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1694 /** Get the integer X axis orientation
1695 @return NATURAL means increasing to the right. */
1697 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1698 /** Is the integer X axis NATURAL?
1699 @return true means increasing to the right. */
1700 inline bool isIntAxOrientationNaturalX() { return (intAxOrientationX == intAxisOrientation::NATURAL); }
1701 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1702 /** Set the integer X axis orientation
1703 @param orientation The orientation (INVERTED or NATURAL) */
1704 inline void setIntAxOrientationX(intAxisOrientation orientation) { intAxOrientationX = orientation; }
1705 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1706 /** Get the integer Y axis orientation
1707 @return NATURAL means increasing in the upward direction. */
1708 inline bool isIntAxOrientationNaturalY() { return (intAxOrientationY == intAxisOrientation::NATURAL); }
1709 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1710 /** Is the integer Y axis orientation NATURAL?
1711 @return NATURAL means increasing in the upward direction. */
1713 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1714 /** Set the integer Y axis orientation
1715 @param orientation The orientation (INVERTED or NATURAL) */
1716 inline void setIntAxOrientationY(intAxisOrientation orientation) { intAxOrientationY = orientation; }
1717 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1718 /** Set the integer axis orientation to default (NATURAL for both X and Y axes) */
1719 inline void setIntAxisDefaultOrientation() { setIntAxOrientationX(intAxisOrientation::NATURAL); setIntAxOrientationY(intAxisOrientation::NATURAL); }
1720 //@}
1721
1722 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1723 /** @name Accessor Methods */
1724 //@{
1725 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1726 /** @return The number of pixels in the x direction. */
1727 inline intCrdT getNumPixX() const { return numPixX; }
1728 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1729 /** @return The number of pixels in the y direction. */
1730 inline intCrdT getNumPixY() const { return numPixY; }
1731 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1732 /** Returns a pointer to the raw pixel store.
1733 This generally violates the ramCanvasTpl object interface; however, this may be required for performance.
1734 @return The number a pointer to the raw pixel store. */
1735 colorT *getPixels() { return pixels; }
1736 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1737 /** Return a clone (a copy) of the raw pixel store.
1738 This function copies the internal pixel store and returns a pointer to this copy.
1739 @return Pointer to a copy of the raw pixel store. */
1740 colorT *clonePixels();
1741 //@}
1742
1743 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1744 /** @name Real Coordinate Accessor Methods */
1745 //@{
1746 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1747 fltCrdT getMinRealX() { return minRealX; } //!< x coord of min (real coord)
1748 fltCrdT getMaxRealX() { return maxRealX; } //!< x coord of max (real coord)
1749 fltCrdT getMinRealY() { return minRealY; } //!< y coord of min (real coord)
1750 fltCrdT getMaxRealY() { return maxRealY; } //!< y coord of max (real coord)
1751 fltCrdT getPixWidX() { return pixWidX; } //!< Width of a pixel (real coord)
1752 fltCrdT getPixWidY() { return pixWidY; } //!< Height of a pixel (real coord)
1753 fltCrdT getCanvasWidX() { return canvasWidX; } //!< Width of the display (real coord)
1754 fltCrdT getCanvasWidY() { return canvasWidY; } //!< height of the display(real coord)
1755 fltCrdT getCanvasWidD() { return std::hypot(canvasWidX, canvasWidY); } //!< Width of the display (real coord)
1756 //@}
1757
1758 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1759 /** @name Pixel Value Accessor Methods */
1760 //@{
1761 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1762 /** Returns a copy of the color at the given coordinates. */
1763 inline colorT getPxColor(intCrdT x, intCrdT y) const;
1764 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1765 /** @overload */
1766 inline colorT getPxColor(fltCrdT x, fltCrdT y) const { return getPxColor(real2intX(x), real2intY(y)); }
1767 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1768 /** @overload */
1769 inline colorT getPxColor(pointIntType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1770 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1771 /** @overload */
1772 inline colorT getPxColor(pointFltType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1773 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1774 /** Returns a copy of the color at the given coordinates wrapping x & y if out of range. */
1775 inline colorT getPxColorWrap(intCrdT x, intCrdT y) const { return getPxColorNC(mjr::math::ivl::wrapCO(x, numPixX), mjr::math::ivl::wrapCO(y, numPixY)); }
1776 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1777 /** @overload */
1778 inline colorT getPxColorWrap(fltCrdT x, fltCrdT y) const { return getPxColorWrap(real2intX(x), real2intY(y)); }
1779 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1780 /** @overload */
1781 inline colorT getPxColorWrap(pointIntType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y); }
1782 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1783 /** @overload */
1784 inline colorT getPxColorWrap(pointFltType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y); }
1785 //@}
1786
1787 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1788 /** @name Pixel Channel Value Accessor Methods. */
1789 //@{
1790 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1791 /** Returns a copy of the color channel value at the given coordinates */
1792 template <int chanNum>
1793 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1794 inline colorT getPxColorChan(intCrdT x, intCrdT y) const { return getPxColor(x, y).getChanNC(chanNum); }
1795 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1796 /** @overload */
1797 template <int chanNum>
1798 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1799 inline colorT getPxColorChan(fltCrdT x, fltCrdT y) const { return getPxColor(x, y).getChanNC(chanNum); }
1800 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1801 /** @overload */
1802 template <int chanNum>
1803 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1804 inline colorT getPxColorChan(pointIntType thePoint) const { return getPxColor(thePoint).getChanNC(chanNum); }
1805 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1806 /** @overload */
1807 template <int chanNum>
1808 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1809 inline colorT getPxColorChan(pointFltType thePoint) const { return getPxColor(thePoint).getChanNC(chanNum); }
1810 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1811 /** Returns a copy of the color channel value at the given coordinates wrapping x & y if out of range. */
1812 template <int chanNum>
1813 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1814 inline colorChanType getPxColorChanWrap(intCrdT x, intCrdT y) const { return getPxColorWrap(x, y).getChanNC(chanNum); }
1815 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1816 /** @overload */
1817 template <int chanNum>
1818 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1819 inline colorChanType getPxColorChanWrap(fltCrdT x, fltCrdT y) const { return getPxColorWrap(real2intX(x), real2intY(y)).getChanNC(chanNum); }
1820 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1821 /** @overload */
1822 template <int chanNum>
1823 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1824 inline colorChanType getPxColorChanWrap(pointIntType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y).getChanNC(chanNum); }
1825 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1826 /** @overload */
1827 template <int chanNum>
1828 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1829 inline colorChanType getPxColorChanWrap(pointFltType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y).getChanNC(chanNum); }
1830 //@}
1831
1832 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1833 /** @name Pixel Value Accessor with Interpolation Methods */
1834 //@{
1835 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1836 /** Returns the interpolated color value at the the given coordinates using the given interpolation method.
1837 @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)
1838 @param y The y coordinate
1839 @param interpMethod The interpolation method (default: interpolationType::BILINEAR)
1840 @return Interpolated color value */
1841 colorT getPxColorInterpolate(double x, double y, interpolationType interpMethod = interpolationType::BILINEAR);
1842 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1843 /** Returns the bilinear interpolated color value at the the given coordinates.
1844 @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)
1845 @param y The y coordinate
1846 @return Interpolated color value */
1847 colorT getPxColorInterpBLin(double x, double y);
1848 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1849 /** Returns the truncated interpolated color value at the the given coordinates.
1850 @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)
1851 @param y The y coordinate
1852 @return Interpolated color value */
1853 colorT getPxColorInterpTrunc(double x, double y);
1854 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1855 /** Returns the nearest neighbor interpolated color value at the the given coordinates.
1856 @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)
1857 @param y The y coordinate
1858 @return Interpolated color value */
1859 colorT getPxColorInterpNear(double x, double y);
1860 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1861 /** Returns the average 4 interpolated color value at the the given coordinates.
1862 @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)
1863 @param y The y coordinate
1864 @return Interpolated color value */
1865 colorT getPxColorInterpAvg4(double x, double y);
1866 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1867 /** Returns the average 9 interpolated color value at the the given coordinates.
1868 @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)
1869 @param y The y coordinate
1870 @return Interpolated color value */
1871 colorT getPxColorInterpAvg9(double x, double y);
1872 //@}
1873
1874 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1875 /** @name NC stands for No Checks and No Clipping */
1876 /** 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
1877 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
1878 very careful code that handles clipping and error checking by itself -- a good line drawing algorithm for example. */
1879 //@{
1880 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1881 /** Draw a point with no clipping or bounds checking.
1882 @param x The x coordinate of the point to be drawn
1883 @param y The y coordinate of the point to be drawn
1884 @param color The color to draw the point. */
1885 void drawPointNC(intCrdT x, intCrdT y, colorArgType color);
1886 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1887 /** Get the default point to the specified coordinates with no clipping or bounds checking.
1888 @param x The x coordinate of the point
1889 @param y The y coordinate of the point */
1890 inline colorT getPxColorNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1891 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1892 /** Returns a reference to the color object for the given pixel with no clipping or bounds checking.
1893 @param x The x coordinate of the point
1894 @param y The y coordinate of the point
1895 @return Reference to the color object associated with the specified point */
1896 inline colorT& getPxColorRefNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1897 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1898 /** Draw a horizontal line with no clipping or bounds checking.
1899 @param xMin The MINIMUM x coordinate of the line to be drawn
1900 @param xMax The MAXIMUM x coordinate of the line to be drawn
1901 @param yConst The y coordinate at which the line is to be drawn
1902 @param color The color to draw the line */
1903 inline void drawHorzLineNC(intCrdT xMin, intCrdT xMax, intCrdT yConst, colorArgType color) { for(intCrdT x=xMin;x<=xMax;x++) drawPointNC(x, yConst, color); }
1904 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1905 /** Draw a vertical line with no clipping or bounds checking.
1906 @param yMin The MINIMUM y coordinate of the line to be drawn
1907 @param yMax The MAXIMUM y coordinate of the line to be drawn
1908 @param xConst The x coordinate at which the line is to be drawn
1909 @param color The color to draw the line */
1910 inline void drawVertLineNC(intCrdT yMin, intCrdT yMax, intCrdT xConst, colorArgType color) { for(intCrdT y=yMin;y<=yMax;y++) drawPointNC(xConst, y, color); }
1911 //@}
1912
1913 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1914 /** @name S stands for Simple */
1915 //@{
1916 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1917 /** Draw a point without any special drawing options.
1918 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
1919 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
1920 careful code that handles clipping and error checking and drawing options by itself -- an image filter algorithm for example. Note that enableDrawModes
1921 is ignored.
1922 @param x The x coordinate of the point
1923 @param y The y coordinate of the point
1924 @param color The color with which to draw the point */
1925 inline void drawPointS(intCrdT x, intCrdT y, colorArgType color) { pixels[numPixX * y + x] = color; }
1926 //@}
1927
1928 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1929 /** @name Canvas Level Colorization.
1930 These are tools designed to make things like escape time fractals very easy to create.
1931
1932 @warning These functions are experimental! Functionality and API are likely to change in the future.
1933
1934 */
1935 //@{
1936 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1937 void colorizeFltCanvas(std::function<colorT (fltCrdT, fltCrdT)> cFun);
1938 void colorizeFltCanvas(std::function<colorT (pointFltType)> cFun);
1939
1940 void colorizeIntCanvas(std::function<colorT (intCrdT, intCrdT)> cFun);
1941 void colorizeIntCanvas(std::function<colorT (pointIntType)> cFun);
1942 //@}
1943
1944 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1945 /** @name Canvas Level Statistical Computation.
1946 */
1947 //@{
1948 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1949 intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
1950 intCrdT retCount = 0;
1951 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
1952 if(x1 > x2)
1953 std::swap(x1, x2);
1954 if(y1 > y2)
1955 std::swap(y1, y2);
1956 for(intCrdT y=y1;y<=y2;y++)
1957 for(intCrdT x=x1;x<=x2;x++)
1958 //if ( !(getPxColor(x, y).isBlack()))
1959 if ( !(getPxColorRefNC(x, y).isBlack()))
1960 retCount++;
1961 }
1962 return(retCount);
1963 }
1964 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1966 return statNumNonZeroPixels(0, 0, numPixX-1, numPixY-1);
1967 }
1968 //@}
1969 };
1970
1971 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1972 // Constructor
1973 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1974 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1984
1985 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1986 // Copy Constructor
1987 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1988 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1990 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1991 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1992 pixels = new colorT[theCanvas.numPixX * theCanvas.numPixY];
1993 pixelsE = pixels + (theCanvas.numPixX * theCanvas.numPixY);
1998 drawMode = theCanvas.drawMode;
1999 for(intCrdT y=0; y<numPixY; y++)
2000 for(intCrdT x=0; x<numPixX; x++)
2001 getPxColorRefNC(x, y) = theCanvas.getPxColorRefNC(x, y);
2002 }
2003
2004 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2005 // Move constructor
2006 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2007 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2019
2020////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2021// Move assignment operator
2022 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2023 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2026 if (this != &theCanvas) {
2027 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
2028 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
2033 drawMode = theCanvas.drawMode;
2034 pixels = theCanvas.pixels;
2035 pixelsE = theCanvas.pixelsE;
2036 }
2037 return *this;
2038 }
2039
2040////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2041 // Normal Constructor
2042 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2043 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2044 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
2045 newIntCoordsNC(numPixX_p, numPixY_p);
2046 newRealCoords(minRealX_p, maxRealX_p, minRealY_p, maxRealY_p);
2047 pixels = new colorT[numPixX * numPixY];
2048 pixelsE = pixels + (numPixX * numPixY);
2053 }
2054
2055////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2056 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2057 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2059 if(pixels != NULL) {
2060 delete[] pixels;
2061 pixels = NULL;
2062 }
2063 }
2064
2065////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2066 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2067 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2068 inline void
2070 if(numPixX_p > intCrdMax) {
2071 throw std::invalid_argument("newIntCoordsNC: numPixX_p argument too large.");
2072 } else if (numPixY_p > intCrdMax) {
2073 throw std::invalid_argument("newIntCoordsNC: numPixY_p argument too large.");
2074 } else {
2075 numPix = numPixX_p * numPixY_p;;
2076 numPixX = numPixX_p;
2077 numPixY = numPixY_p;
2078 }
2079 }
2080
2081////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2082 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2083 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2084 inline void
2085 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
2086 if(minRealX_p > maxRealX_p) {
2087 throw std::invalid_argument("newRealCoords: minRealX_p > maxRealX_p.");
2088 } else if (minRealY_p > maxRealY_p) {
2089 throw std::invalid_argument("newRealCoords: minRealY_p > maxRealY_p.");
2090 } else {
2091 minRealX = minRealX_p;
2092 maxRealX = maxRealX_p;
2093 minRealY = minRealY_p;
2094 maxRealY = maxRealY_p;
2095 updRealCoords();
2096 }
2097 }
2098
2099////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2100 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2101 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2102 inline void
2106 pixWidX = (numPixX == 0 ? 0 : canvasWidX / numPixX); // This will cause /0 later if anyone tries to use a coordinate conversion
2107 pixWidY = (numPixY == 0 ? 0 : canvasWidY / numPixY); // This will cause /0 later if anyone tries to use a coordinate conversion
2108 }
2109
2110////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2111 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2112 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2113 inline void
2115 for(intCrdT y=0; y<numPixY; y++)
2116 for(intCrdT x=0; x<numPixX; x++)
2117 getPxColorRefNC(x, y).setChanToMin(chan);
2118 }
2119
2120////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2121 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2122 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2123 inline void
2125 for(intCrdT y=0; y<numPixY; y++)
2126 for(intCrdT x=0; x<numPixX; x++)
2127 getPxColorRefNC(x, y).setChanToMax(chan);
2128 }
2129
2130////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2131 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2132 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2133 inline void
2135 ////// Diffrent ways to do it -- unless otherwise noted, all of them are about the same performance with GCC if colorT has a fast mask
2136
2137 //// Use std:memset
2138 // std::memset((void*)pixels, 0, numPix*sizeof(colorT));
2139
2140 //// Use std::fill
2141 // colorT black;
2142 // black.setToBlack();
2143 // std::fill(pixels, pixelsE, black);
2144
2145 //// Loop over pixel array
2146 // for(colorT* p=pixels; p<pixelsE; p++)
2147 // p->setToBlack();
2148
2149 //// loop over x & y coordinates
2150 for(intCrdT y=0; y<numPixY; y++)
2151 for(intCrdT x=0; x<numPixX; x++)
2152 getPxColorRefNC(x, y).setToBlack();
2153
2154 //// Call clrCanvas with black (this one is *way* slower)
2155 // clrCanvas(colorT(colorCornerEnum::BLACK));
2156 }
2157
2158////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2159 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2160 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2161 inline void
2163 for(intCrdT y=0; y<numPixY; y++)
2164 for(intCrdT x=0; x<numPixX; x++)
2165 getPxColorRefNC(x, y).setToWhite();
2166 }
2167
2168////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2169 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2170 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2171 inline void
2175
2176////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2177 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2178 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2179 inline void
2181 for(intCrdT y=0; y<numPixY; y++)
2182 for(intCrdT x=0; x<numPixX; x++)
2183 drawPointS(x, y, color);
2184 }
2185
2186////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2187 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2188 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2189 void
2191 colorChanType cmin = colorT::maxChanVal;
2192 colorChanType cmax = colorT::minChanVal;
2193 for(intCrdT y=0;y<numPixY;y++) {
2194 for(intCrdT x=0;x<numPixX;x++) {
2195 colorT daColor = getPxColorNC(x, y);
2196 colorChanType curMin = daColor.getMinC();
2197 colorChanType curMax = daColor.getMaxC();
2198 if(curMax > cmax)
2199 cmax = curMax;
2200 if(curMin < cmin)
2201 cmin = curMin;
2202 }
2203 }
2204 if(cmax-cmin > 0) {
2205 double c = 1.0 * static_cast<double>(colorT::maxChanVal-colorT::minChanVal) / static_cast<double>(cmax-cmin);
2206 double b = static_cast<double>(colorT::maxChanVal) - 1.0 * c * static_cast<double>(cmax);
2207 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScale, c, b);
2208 }
2209 }
2210
2211////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2212 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2213 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2214 void
2216 colorT cmin; cmin.setChans(cmin.maxChanVal);
2217 colorT cmax; cmax.setChans(cmin.minChanVal);
2218 for(intCrdT y=0;y<numPixY;y++) {
2219 for(intCrdT x=0;x<numPixX;x++) {
2220 colorT daColor = getPxColorNC(x, y);
2221 cmin.tfrmMin(daColor);
2222 cmax.tfrmMax(daColor);
2223 }
2224 }
2225 colorChanType absCompMin = cmin.getMinC();
2226 colorChanType absCompMax = cmax.getMaxC();
2227 if(absCompMax-absCompMin > 0) {
2228 double rc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getRed()-cmin.getRed());
2229 double rb = cmin.maxChanVal - 1.0*rc*cmax.getRed();
2230 double gc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getGreen()-cmin.getGreen());
2231 double gb = cmin.maxChanVal - 1.0*gc*cmax.getGreen();
2232 double bc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getBlue()-cmin.getBlue());
2233 double bb = cmin.maxChanVal - 1.0*bc*cmax.getBlue();
2234 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScaleRGB, rc, rb, gc, gb, bc, bb);
2235 }
2236 }
2237
2238////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2239 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2240 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2241 inline void
2243 for(intCrdT y=0; y<numPixY; y++)
2244 for(intCrdT x=0; x<numPixX; x++)
2245 f(getPxColorRefNC(x, y));
2246 }
2247
2248////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2249 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2250 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2251 inline void
2253 for(intCrdT y=0; y<numPixY; y++)
2254 for(intCrdT x=0; x<numPixX; x++)
2255 (getPxColorRefNC(x, y).*HPT)();
2256 }
2257
2258////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2259 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2260 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2261 inline void
2263 for(intCrdT y=0; y<numPixY; y++)
2264 for(intCrdT x=0; x<numPixX; x++)
2265 (getPxColorRefNC(x, y).*HPT)(arg1);
2266 }
2267
2268////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2269 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2270 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2271 inline void
2272 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT arg1, colorT arg2) {
2273 for(intCrdT y=0; y<numPixY; y++)
2274 for(intCrdT x=0; x<numPixX; x++)
2275 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2276 }
2277
2278////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2279 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2280 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2281 inline void
2282 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3) {
2283 for(intCrdT y=0; y<numPixY; y++)
2284 for(intCrdT x=0; x<numPixX; x++)
2285 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2286 }
2287
2288////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2289 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2290 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2291 inline void
2292 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3, colorT arg4) {
2293 for(intCrdT y=0; y<numPixY; y++)
2294 for(intCrdT x=0; x<numPixX; x++)
2295 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2296 }
2297
2298////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2299 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2300 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2301 inline void
2303 for(intCrdT y=0; y<numPixY; y++)
2304 for(intCrdT x=0; x<numPixX; x++)
2305 (getPxColorRefNC(x, y).*HPT)(arg1);
2306 }
2307
2308////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2309 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2310 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2311 inline void
2312 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int arg1, int arg2) {
2313 for(intCrdT y=0; y<numPixY; y++)
2314 for(intCrdT x=0; x<numPixX; x++)
2315 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2316 }
2317
2318////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2319 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2320 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2321 inline void
2322 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int arg1, int arg2, int arg3) {
2323 for(intCrdT y=0; y<numPixY; y++)
2324 for(intCrdT x=0; x<numPixX; x++)
2325 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2326 }
2327
2328////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2329 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2330 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2331 inline void
2332 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int arg1, int arg2, int arg3, int arg4) {
2333 for(intCrdT y=0; y<numPixY; y++)
2334 for(intCrdT x=0; x<numPixX; x++)
2335 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2336 }
2337
2338////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2339 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2340 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2341 inline void
2343 for(intCrdT y=0; y<numPixY; y++)
2344 for(intCrdT x=0; x<numPixX; x++)
2345 (getPxColorRefNC(x, y).*HPT)(arg1);
2346 }
2347
2348////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2349 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2350 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2351 inline void
2352 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double arg1, double arg2) {
2353 for(intCrdT y=0; y<numPixY; y++)
2354 for(intCrdT x=0; x<numPixX; x++)
2355 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2356 }
2357
2358////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2359 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2360 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2361 inline void
2362 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double arg1, double arg2, double arg3) {
2363 for(intCrdT y=0; y<numPixY; y++)
2364 for(intCrdT x=0; x<numPixX; x++)
2365 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2366 }
2367
2368////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2369 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2370 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2371 inline void
2372 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double),
2373 double arg1, double arg2, double arg3, double arg4) {
2374 for(intCrdT y=0; y<numPixY; y++)
2375 for(intCrdT x=0; x<numPixX; x++)
2376 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2377 }
2378
2379////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2380 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2381 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2382 inline void
2383 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double),
2384 double arg1, double arg2, double arg3, double arg4, double arg5) {
2385 for(intCrdT y=0; y<numPixY; y++)
2386 for(intCrdT x=0; x<numPixX; x++)
2387 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5);
2388 }
2389
2390////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2391 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2392 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2393 inline void ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double),
2394 double arg1, double arg2, double arg3, double arg4, double arg5, double arg6) {
2395 for(intCrdT y=0; y<numPixY; y++)
2396 for(intCrdT x=0; x<numPixX; x++)
2397 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5, arg6);
2398 }
2399
2400////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2401 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2402 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2404 const ramCanvasTpl &theCanvas,
2405 intCrdT trgX, intCrdT trgY,
2406 intCrdT wide, intCrdT tall,
2407 intCrdT srcX, intCrdT srcY) {
2408 // Figure out real default width
2409 if(wide < 0)
2410 wide = numPixX-trgX;
2411
2412 // Make sure wide is not wider than current canvas.
2413 if(wide > (numPixX-srcX))
2414 wide = theCanvas.getNumPixX()-srcX;
2415
2416 // Make sure wide is not wider than given canvas.
2417 if(wide > (theCanvas.getNumPixX()-srcX))
2418 wide = theCanvas.getNumPixX()-srcX;
2419
2420 // Figure out real default tall
2421 if(tall < 0)
2422 tall = numPixY-srcY;
2423
2424 // Make sure tall is not taller than current canvas.
2425 if(tall > (numPixY-srcY))
2426 tall = numPixY-srcY;
2427
2428 // Make sure tall is not taller than given canvas.
2429 if(tall > (theCanvas.getNumPixY()-srcY))
2430 tall = theCanvas.getNumPixY()-srcY;
2431
2432 intCrdT xMax = trgX+wide;
2433 intCrdT yMax = trgY+tall;
2434 for(intCrdT y=trgY, ys=srcY; y<yMax; y++, ys++)
2435 for(intCrdT x=trgX, xs=srcX; x<xMax; x++, xs++)
2436 (getPxColorRefNC(x, y).*HPT)(theCanvas.getPxColor(xs, ys));
2437 }
2438
2439////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2440 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2441 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2442 void
2443 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
2444 moveTo(x2, y2); // Do this first
2445 intCrdT x, y;
2446 if(y1 == y2) { // slope = 0
2447 if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
2448 return;
2449 if(x1 > x2) // . Fix point ordering
2450 std::swap(x1, x2);
2451 if(x1 < 0) // . Clip left
2452 x1 = 0;
2453 if(x2 >= numPixX) // . Clip right
2454 x2 = numPixX - 1;
2455 drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
2456 } else if(x1 == x2) { // slope = infinity
2457 if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
2458 return;
2459 if(y1 > y2) // . Fix point ordering
2460 std::swap(y1, y2);
2461 if(y1 < 0) // . Clip top
2462 y1 = 0;
2463 if(y2 >= numPixY) // . Clip bottom
2464 y2 = numPixY - 1;
2465 drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
2466 } else { // Slope is not infinity or 0...
2467 int dx, dy;
2468 if(x1 > x2) { // . Fix point ordering
2469 std::swap(x1, x2);
2470 std::swap(y1, y2);
2471 }
2472 dx = x2 - x1; // . Compute the slope
2473 dy = y2 - y1;
2474 if(dx == dy) { // . Slope = 1
2475 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
2476 return;
2477 if(x1 < 0) { // .. Clip left
2478 y1 = y1 - x1;
2479 x1 = 0;
2480 }
2481 if(y1 < 0) { // .. Clip top
2482 x1 = x1 - y1;
2483 y1 = 0;
2484 }
2485 if(x2 >= numPixX) { // .. Clip right
2486 y2 = y2 - (x2 - numPixX) - 1;
2487 x2 = numPixX - 1;
2488 }
2489 if(y2 >= numPixY) { // .. Clip bottom
2490 x2 = x2 - (y2 - numPixY) - 1;
2491 y2 = numPixY - 1;
2492 }
2493 for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
2494 drawPointNC(x, y, color);
2495 } else if(dx == -dy) { // . Slope = -1
2496 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
2497 return;
2498 if(x1 < 0) { // .. Clip left
2499 y1 = y1 + x1;
2500 x1 = 0;
2501 }
2502 if(x2 >= numPixX) { // .. Clip right
2503 y2 = y2 + (x2 - (numPixX - 1));
2504 x2 = numPixX - 1;
2505 }
2506 if(y2 < 0) { // .. Clip top
2507 x2 = x2 + y2;
2508 y2 = 0;
2509 }
2510 if(y1 >= numPixY) { // .. Clip bottom
2511 x1 = x1 + (y1 - (numPixY - 1));
2512 y1 = numPixY - 1;
2513 }
2514 for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
2515 drawPointNC(x, y, color);
2516 } else { // . Slope != 1, -1, 0, \infinity
2517 int s, dx2, dy2;
2518 dx2 = 2*dx;
2519 dy2 = 2*dy;
2520 if(dy > 0) { // .. Positive Slope
2521 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
2522 return;
2523 if(x1 < 0) { // ... Clip left
2524 y1 = (int)(1.0*y1-x1*dy/dx);
2525 x1 = 0;
2526 }
2527 if(y1 < 0) { // ... Clip top
2528 x1 = (int)(1.0*x1-y1*dx/dy);
2529 y1 = 0;
2530 }
2531 if(x2 >= numPixX) { // ... Clip right
2532 y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
2533 x2 = numPixX - 1;
2534 }
2535 if(y2 >= numPixY) { // ... Clip bottom
2536 x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
2537 y2 = numPixY - 1;
2538 }
2539// MJR TODO NOTE drawLine: We use drawPoint instead of drawPointNC, can we make an off canvas decesion instead? Similar case down below.
2540 if(dx > dy) { // ... 0 < Slope < 1
2541 s = dy2 - dx;
2542 x=x1;
2543 y=y1;
2544 while(x<=x2) { // .... Draw Line
2545 drawPoint(x, y, color);
2546 if(s < 0) {
2547 s += dy2;
2548 } else {
2549 y++;
2550 s += dy2 - dx2;
2551 }
2552 x++;
2553 }
2554 } else { // ... 1 < Slope < infinity
2555 s = dy - dx2;
2556 x=x1;
2557 y=y1;
2558 while(y<=y2) { // .... Draw Line
2559 drawPoint(x, y, color);
2560 if(s > 0) {
2561 s -= dx2;
2562 } else {
2563 x++;
2564 s += dy2 - dx2;
2565 }
2566 y++;
2567 }
2568 }
2569 } else { // .. Negative Slope
2570 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
2571 return;
2572 if(x1 < 0) { // ... Clip left
2573 y1 = (int)(1.0*y1-x1*dy/dx);
2574 x1 = 0;
2575 }
2576 if(y2 < 0) { // ... Clip top
2577 x2 = (int)(1.0*x2-y2*dx/dy);
2578 y2 = 0;
2579 }
2580 if(x2 >= numPixX) { // ... Clip right
2581 y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
2582 x2 = numPixX - 1;
2583 }
2584 if(y1 >= numPixY) { // ... Clip bottom
2585 x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
2586 y1 = numPixY - 1;
2587 }
2588 if(dx > -dy) { // ... 0 > Slope > -infinity
2589 s = dy2 + dx;
2590 x=x1;
2591 y=y1;
2592 while(x<=x2) { // .... Draw Line
2593 drawPoint(x, y, color);
2594 if(s > 0) {
2595 s += dy2;
2596 } else {
2597 y--;
2598 s += dy2 + dx2;
2599 }
2600 x++;
2601 }
2602 } else { // ... -1 > Slope > -inf
2603 s = dy + dx2;
2604 x=x1;
2605 y=y1;
2606 while(y>=y2) { // .... Draw Line
2607 drawPoint(x, y, color);
2608 if(s < 0) {
2609 s += dx2;
2610 } else {
2611 x++;
2612 s += dy2 + dx2;
2613 }
2614 y--;
2615 }
2616 }
2617 }
2618 }
2619 }
2620 }
2621
2622////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2623 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2624 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2625 void
2627 newIntCoordsNC(-1, -1);
2628 if(pixels != NULL) {
2629 delete[] pixels;
2630 pixels=NULL;
2631 pixelsE=NULL;
2632 }
2633 }
2634
2635////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2636 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2637 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2638 void
2639 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY) {
2640 freeCanvas();
2641 newIntCoordsNC(new_numPixX, new_numPixY);
2642 updRealCoords();
2643 if(new_pixels != NULL)
2644 pixels = new_pixels;
2645 if(pixels == NULL)
2646 pixelsE = NULL;
2647 else
2648 pixelsE = pixels+(new_numPixX * new_numPixY);
2649 }
2650
2651////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2652 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2653 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2654 void
2656 if((numPixX_p<=0) || (numPixY_p<=0)) {
2657 freeCanvas();
2658 } else {
2659 if( (numPixX_p!=numPixX) || (numPixY_p!=numPixY) ) {
2660 colorT *new_pixels = new colorT[numPixX_p * numPixY_p];
2661 rePointPixels(new_pixels, numPixX_p, numPixY_p);
2662 } else {
2663 // Don't really do anything as the new size is the same as the old size...
2664 }
2665 }
2666 }
2667
2668////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2669 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2670 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2671 void
2673 reallocCanvas(new_numPixX_p, new_numPixY_p);
2674 }
2675
2676////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2677 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2678 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2679 void
2680 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1, intCrdT y1, colorArgType color) {
2681 if( (new_numPixX_p != numPixX) || (new_numPixY_p != numPixY) ) {
2682
2683 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2684
2685 // Fill it up with the default color. Should only draw the ones that need it, but computers are fast...
2686 for(intCrdT y=0;y<new_numPixY_p;y++)
2687 for(intCrdT x=0;x<new_numPixX_p;x++)
2688 new_pixels[new_numPixX_p * (y) + (x)] = color;
2689
2690 intCrdT yMax = std::min(numPixY+y1, new_numPixY_p);
2691 intCrdT xMax = std::min(numPixX+x1, new_numPixX_p);
2692
2693 // Copy the old image to the new space.
2694 if ((x1 < new_numPixX_p) && (y1 < new_numPixY_p))
2695 for(intCrdT y=y1;y<yMax;y++)
2696 for(intCrdT x=x1;x<xMax;x++)
2697 new_pixels[new_numPixX_p * (y) + (x)] = getPxColor(x-x1, y-y1);
2698
2699 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2700 }
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
2707 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
2708 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
2709 if(x1 > x2)
2710 std::swap(x1, x2);
2711 if(y1 > y2)
2712 std::swap(y1, y2);
2713 intCrdT xp, yp, x, y;
2714 intCrdT new_numPixX_p = x2-x1+1;
2715 intCrdT new_numPixY_p = y2-y1+1;
2716 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2717
2718 // Copy the old image to the new space.
2719 for(y=y1,yp=0;y<=y2;y++,yp++)
2720 for(x=x1,xp=0;x<=x2;x++,xp++)
2721 new_pixels[new_numPixX_p * yp + xp] = getPxColor(x, y);
2722
2723 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2724 }
2725 }
2726
2727////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2728 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2729 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2730 void
2732 for(intCrdT y=0; y<numPixY/2; y++)
2733 for(intCrdT x=0; x<numPixX; x++) {
2734 colorT aColor = getPxColor(x, numPixY-y-1);
2735 drawPointNC(x, numPixY-y-1, getPxColor(x, y));
2736 drawPointNC(x, y, aColor);
2737 }
2738 }
2739
2740////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2741 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2742 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2743 void
2745 for(intCrdT x=0; x<numPixX/2; x++)
2746 for(intCrdT y=0; y<numPixY; y++) {
2747 colorT aColor = getPxColor(numPixX-x-1, y);
2748 drawPointNC(numPixX-x-1, y, getPxColor(x, y));
2749 drawPointNC(x, y, aColor);
2750 }
2751 }
2752
2753////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2754 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2755 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2756 void
2758 intCrdT new_numPixX_p = numPixY;
2759 intCrdT new_numPixY_p = numPixX;
2760 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2761 for(intCrdT y=0; y<numPixY; y++)
2762 for(intCrdT x=0; x<numPixX; x++)
2763 new_pixels[new_numPixX_p * (x/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2764 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2765 }
2766
2767////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2768 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2769 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2770 void
2772 intCrdT new_numPixX_p = numPixY;
2773 intCrdT new_numPixY_p = numPixX;
2774 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2775 for(intCrdT y=0; y<numPixY; y++)
2776 for(intCrdT x=0; x<numPixX; x++)
2777 new_pixels[new_numPixX_p * (numPixX-x-1/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2778 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2779 }
2780
2781////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2782 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2783 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2784 void
2786 intCrdT new_numPixX_p = numPixY;
2787 intCrdT new_numPixY_p = numPixX;
2788 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2789 for(intCrdT y=0; y<numPixY; y++)
2790 for(intCrdT x=0; x<numPixX; x++)
2791 new_pixels[new_numPixX_p * (x/*y-crd*/) + (numPixY-y-1/*x-crd*/)] = getPxColor(x, y);
2792 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2793 }
2794
2795////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2796 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2797 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2798 void
2800 intCrdT new_numPixX_p = numPixX;
2801 intCrdT new_numPixY_p = numPixY;
2802 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2803 for(intCrdT y=0; y<numPixY; y++)
2804 for(intCrdT x=0; x<numPixX; x++)
2805 new_pixels[new_numPixX_p * (numPixY-y-1/*y-crd*/) + (numPixX-x-1/*x-crd*/)] = getPxColor(x, y);
2806 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2807 }
2808
2809////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2810 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2811 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2814 unsigned int endiannessProbe = 1;
2815 if(((char *)&endiannessProbe)[0]) {
2816 return endianType::LITTLE;
2817 } else {
2818 return endianType::BIG;
2819 }
2820 }
2821
2822////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2823 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2824 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2825 inline void
2828 int numBytes,
2829 uint64_t data) {
2830 if(numBytes>0) {
2831 if (numBytes == 1) {
2832 uint8_t tmp = (data & 0xff);
2833 oStream.write((const char *)&tmp, 1);
2834 } else {
2835 if (numBytes<9) {
2836 endianType endiannessToUse = (endianness == endianType::AUTO ? platformEndianness() : endianness);
2837 if(endiannessToUse == endianType::LITTLE) {
2838 for(int curByte=0; curByte<numBytes; curByte++) {
2839 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2840 oStream.write((const char *)&tmp, 1);
2841 }
2842 } else {
2843 for(int curByte=(numBytes-1); curByte>=0; curByte--) {
2844 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2845 oStream.write((const char *)&tmp, 1);
2846 }
2847 }
2848 }
2849 }
2850 }
2851 }
2852
2853////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2854 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2855 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2856 void
2858 for(intCrdT yi=0;yi<numPixY;yi++) {
2859 for(intCrdT xi=0;xi<numPixX;xi++) {
2860 fltCrdT xf = int2realX(xi);
2861 fltCrdT yf = int2realY(yi);
2862 colorT aColor = cFun(xf, yf);
2863 drawPoint(xi, yi, aColor);
2864 }
2865 }
2866 }
2867
2868////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2869 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2870 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2871 void
2873 for(intCrdT yi=0;yi<numPixY;yi++) {
2874 for(intCrdT xi=0;xi<numPixX;xi++) {
2875 pointFltType xyPt(int2realX(xi), int2realY(yi));
2876 colorT aColor = cFun(xyPt);
2877 drawPoint(xi, yi, aColor);
2878 }
2879 }
2880 }
2881
2882////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2883 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2884 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2885 void
2887 for(intCrdT yi=0;yi<numPixY;yi++) {
2888 for(intCrdT xi=0;xi<numPixX;xi++) {
2889 colorT aColor = cFun(xi, yi);
2890 drawPoint(xi, yi, aColor);
2891 }
2892 }
2893 }
2894
2895////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2896 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2897 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2898 void
2900 for(intCrdT yi=0;yi<numPixY;yi++) {
2901 for(intCrdT xi=0;xi<numPixX;xi++) {
2902 pointIntType xyPt(xi, yi);
2903 colorT aColor = cFun(xyPt);
2904 drawPoint(xi, yi, aColor);
2905 }
2906 }
2907 }
2908
2909////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2910 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2911 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2912 inline int
2914
2915 std::ofstream outStream;
2916 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2917 if (outStream.is_open())
2918 outStream.imbue(std::locale::classic());
2919 else
2920 return 1;
2921
2922 if(numPixX < 1) // too skinny
2923 return 6;
2924 if(numPixX > 0xffff) // too wide
2925 return 7;
2926 if(numPixY < 1) // too short
2927 return 8;
2928 if(numPixY > 0xffff) // too tall
2929 return 9;
2930
2931 /* Write header */
2932 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // id length
2933 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colourmaptype
2934 writeUIntToStream(outStream, endianType::LITTLE, 1, 2); // datatypecode: 2 == Truecolor RGB 8-bit, 3 == Monochrome
2935 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit colourmaporigin
2936 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // colurmaplength
2937 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colormapdepth
2938 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit x_origin
2939 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit y_origon
2940 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixX); // Width
2941 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixY); // Height
2942 writeUIntToStream(outStream, endianType::LITTLE, 1, 24); // bits per pixel
2943 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // imagedescriptor
2944
2945 /* Write data */
2946 intCrdT x, y;
2947 /* 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
2948 "for(y=(numPixY-1); y>=0; y--)" and "for(y=0; y<numPixY; y++)". */
2949 bool yNat = isIntAxOrientationNaturalY();
2950 bool xNat = isIntAxOrientationNaturalX();
2951 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
2952 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
2953 colorT aColor = getPxColorRefNC(x, y);
2954 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestBlueChan()));
2955 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestGreenChan()));
2956 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestRedChan()));
2957 }
2958 }
2959 return 0;
2960 }
2961
2962////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2963 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2964 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2965 inline int
2970
2971////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2972 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2973 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2974 template <class rcConT>
2975 inline int
2977
2978 std::ofstream outStream;
2979 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2980 if (outStream.is_open())
2981 outStream.imbue(std::locale::classic());
2982 else
2983 return 1;
2984
2985 outStream << "MJRRAW\n"; // 7 7
2986 outStream << std::setw(19) << std::setfill('0') << pxFilter.getNumPixX() << "x"; // 20 27
2987 outStream << std::setw(19) << std::setfill('0') << pxFilter.getNumPixY() << "y"; // 20 47
2988 outStream << std::setw(27) << std::setfill('0') << rcConT::colorType::channelCount << "c"; // 28 75
2989 outStream << std::setw(11) << std::setfill('0') << rcConT::colorType::bitsPerChan << "b"; // 12 87
2990 outStream << (rcConT::colorType::chanIsUnsigned ? "UNS" : "SGN") << "s"; // 4 91
2991 outStream << (rcConT::colorType::chanIsInt ? "INT" : "FLT") << "t"; // 4 95
2992 outStream << (platformEndianness() == endianType::LITTLE ? "LTL" : "BIG") << "i"; // 4 99
2993 outStream << "\n"; // 1 100
2994
2995 intCrdT x, y;
2996 /* 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
2997 "for(y=(pxFilter.getNumPixY()-1); y>=0; y--)" and "for(y=0; y<pxFilter.getNumPixY(); y++)". */
2998 bool yNat = !(pxFilter.isIntAxOrientationNaturalY());
2999 bool xNat = pxFilter.isIntAxOrientationNaturalX();
3000 for((yNat?y=0:y=(pxFilter.getNumPixY()-1)); (yNat?y<pxFilter.getNumPixY():y>=0); (yNat?y++:y--)) {
3001 for((xNat?x=0:x=(pxFilter.getNumPixX()-1)); (xNat?x<pxFilter.getNumPixX():x>=0); (xNat?x++:x--)) {
3002 typename rcConT::colorType aColor = pxFilter.getPxColorNC(x, y);
3003 for(int c=0; c<aColor.channelCount; c++) {
3004 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
3005 outStream.write((const char *)&aChanValue, sizeof(colorChanType));
3006 }
3007 }
3008 }
3009 return 0;
3010 }
3011
3012////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3013 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3014 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3015 inline int
3020
3021////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3022 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3023 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3024 template <class rcConT>
3025 inline int
3026 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha) {
3027
3028 if(rcConT::colorType::bitsPerChan < 8) // channels too thin
3029 return 2;
3030 if(rcConT::colorType::bitsPerChan > 0xffff) // channels too fat
3031 return 3;
3032 if(rcConT::colorType::channelCount < 1) // too few channels
3033 return 4;
3034 if(rcConT::colorType::channelCount > 0xffff) // too many channels
3035 return 5;
3036 if(pxFilter.getNumPixX() < 1) // too skinny
3037 return 6;
3038 if(pxFilter.getNumPixX() > 0x7fffffff) // too wide
3039 return 7;
3040 if(pxFilter.getNumPixY() < 1) // too short
3041 return 8;
3042 if(pxFilter.getNumPixY() > 0x7fffffff) // too tall
3043 return 9;
3044 unsigned long bytesPerRow = pxFilter.getNumPixX() * rcConT::colorType::bitsPerChan / 8ul * rcConT::colorType::channelCount;
3045 if(bytesPerRow > 0xffffffff) // rows too big
3046 return 10;
3047 if(bytesPerRow * pxFilter.getNumPixY() > 0xfffffffff) // image too big
3048 return 11;
3049
3050 // //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
3051 const uint16_t tcTIFF_BIGENDIAN = 0x4d4d; /* Magic number for big endian */
3052 const uint16_t tcTIFF_LITTLEENDIAN = 0x4949; /* Magic number for little endian */
3053 const uint16_t tcPHOTOMETRIC_MINISBLACK = 1; /* min value is black */
3054 const uint16_t tcPHOTOMETRIC_RGB = 2; /* RGB color model */
3055 const uint16_t tcORIENTATION_TOPLEFT = 1; /* row 0 top, col 0 lhs */
3056 const uint16_t tcPLANARCONFIG_CONTIG = 1; /* single image plane */
3057 const uint16_t tcRESUNIT_NONE = 1; /* no meaningful units */
3058 const uint16_t tcSAMPLEFORMAT_UINT = 1; /* !unsigned integer data */
3059 const uint16_t tcSAMPLEFORMAT_IEEEFP = 3; /* !IEEE floating point data */
3060
3061 // //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
3062 // const uint16_t tcTIFFTAG_IMAGEWIDTH = 256; /* image width in pixels */
3063 // const uint16_t tcTIFFTAG_IMAGELENGTH = 257; /* image height in pixels */
3064 // const uint16_t tcTIFFTAG_BITSPERSAMPLE = 258; /* bits per channel (sample) */
3065 // const uint16_t tcTIFFTAG_COMPRESSION = 259; /* data compression technique */
3066 // const uint16_t tcTIFFTAG_PHOTOMETRIC = 262; /* photometric interpretation */
3067 // const uint16_t tcTIFFTAG_STRIPOFFSETS = 273; /* offsets to data strips */
3068 // const uint16_t tcTIFFTAG_ORIENTATION = 274; /* +image orientation */
3069 // const uint16_t tcTIFFTAG_SAMPLESPERPIXEL = 277; /* samples per pixel */
3070 // const uint16_t tcTIFFTAG_ROWSPERSTRIP = 278; /* rows per strip of data */
3071 // const uint16_t tcTIFFTAG_STRIPBYTECOUNTS = 279; /* bytes counts for strips */
3072 // const uint16_t tcTIFFTAG_XRESOLUTION = 282; /* pixels/resolution in x */
3073 // const uint16_t tcTIFFTAG_YRESOLUTION = 283; /* pixels/resolution in y */
3074 // const uint16_t tcTIFFTAG_PLANARCONFIG = 284; /* storage organization */
3075 // const uint16_t tcTIFFTAG_RESOLUTIONUNIT = 296; /* units of resolutions */
3076 // const uint16_t tcTIFFTAG_EXTRASAMPLES = 338; /* !info about extra samples */
3077 // const uint16_t tcTIFFTAG_SAMPLEFORMAT = 339; /* !data sample format */
3078
3079 endianType fe = platformEndianness(); // Endian Type
3080 uint16_t endianNum = (fe == endianType::LITTLE ? tcTIFF_LITTLEENDIAN : tcTIFF_BIGENDIAN); // Endianness Magic Number
3081 uint32_t tifWidth = (uint32_t)pxFilter.getNumPixX(); // ImageWidth
3082 uint32_t tifLength = (uint32_t)pxFilter.getNumPixY(); // ImageLength & RowsPerStrip
3083 uint32_t tifSPP = (uint32_t)rcConT::colorType::channelCount; // SamplesPerPixel
3084 uint16_t tifBPS = (uint16_t)(rcConT::colorType::bitsPerChan); // BitsPerSample
3085 uint32_t bytePerSmp = tifBPS / 8; // Bytes per sample
3086 uint32_t tifSBC = tifLength * tifWidth * bytePerSmp * tifSPP; // StripByteCounts
3087 bool haveRGB = tifSPP>=3; // TRUE if this image has RGB data (at least 3 channels)
3088 uint16_t numImgSmp = (haveRGB ? 3 : 1); // Number of samples used for image data (3 for RGB, 1 otherwise)
3089 uint16_t tifPMI = (haveRGB ? tcPHOTOMETRIC_RGB : tcPHOTOMETRIC_MINISBLACK); // PhotometricInterp
3090 uint16_t tifPC = tcPLANARCONFIG_CONTIG; // Planarconfig
3091 uint16_t tifOri = tcORIENTATION_TOPLEFT; // Orientation
3092 uint16_t tifResU = tcRESUNIT_NONE; // Resolution Unit
3093 bool haveXS = !((tifSPP==1) || (tifSPP==3)); // TRUE if this image has ExtraSamples data
3094 bool haveManyXS = tifSPP>4; // TRUE if this image has MORE THAN ONE ExtraSamples data
3095 uint16_t numTags = 1+14 + (haveXS ? 1 : 0); // Number fo tags in this image
3096 bool haveManyBPS = tifSPP>1; // TRUE if this image has MORE THAN ONE BitsPerSample data
3097 uint32_t numXS = tifSPP - numImgSmp; // Number of extra samples
3098 uint32_t xResOff = 14 + 12 * numTags; // XResolution offset
3099 uint32_t yResOff = xResOff + 8; // YResolution offset
3100 uint32_t bpsOff = yResOff + 8; // BitsPerSample offset
3101 uint32_t xsOff = bpsOff + (haveManyBPS ? 2 * tifSPP : 0); // ExtraSamples offset
3102 uint32_t imgOff = xsOff + (haveManyXS ? 2 * numXS : 0); // Image Data offset
3103 uint16_t sampFmt = (rcConT::colorType::chanIsInt ? tcSAMPLEFORMAT_UINT : tcSAMPLEFORMAT_IEEEFP); // SampleFormat (1=unsigned, 3=IEEE)
3104
3105 std::ofstream outStream;
3106 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
3107 if (outStream.is_open())
3108 outStream.imbue(std::locale::classic());
3109 else
3110 return 1;
3111
3112 writeUIntToStream(outStream, fe, 2, endianNum); // Write: little endian magic number
3113 writeUIntToStream(outStream, fe, 2, 42); // Write: TIFF magic number
3114 writeUIntToStream(outStream, fe, 4, 8); // Write: IDF offset
3115 writeUIntToStream(outStream, fe, 2, numTags); // Tag Count
3116 writeUIntToStream(outStream, fe, 2, 0x100); writeUIntToStream(outStream, fe, 2, 4);
3117 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifWidth); // ImageWidth
3118 writeUIntToStream(outStream, fe, 2, 0x101); writeUIntToStream(outStream, fe, 2, 4);
3119 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // ImageLength
3120 writeUIntToStream(outStream, fe, 2, 0x102); writeUIntToStream(outStream, fe, 2, 3);
3121 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifBPS); writeUIntToStream(outStream, fe, 2, 0); // BitsPerSample
3122 writeUIntToStream(outStream, fe, 2, 0x103); writeUIntToStream(outStream, fe, 2, 3);
3123 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, 1); writeUIntToStream(outStream, fe, 2, 0); // Compression
3124 writeUIntToStream(outStream, fe, 2, 0x106); writeUIntToStream(outStream, fe, 2, 3);
3125 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPMI); writeUIntToStream(outStream, fe, 2, 0); // PhotometricIn
3126 writeUIntToStream(outStream, fe, 2, 0x111); writeUIntToStream(outStream, fe, 2, 4);
3127 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, imgOff); // StripOffsets
3128 writeUIntToStream(outStream, fe, 2, 0x112); writeUIntToStream(outStream, fe, 2, 3);
3129 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifOri); writeUIntToStream(outStream, fe, 2, 0); // Orientation
3130 writeUIntToStream(outStream, fe, 2, 0x115); writeUIntToStream(outStream, fe, 2, 3);
3131 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifSPP); writeUIntToStream(outStream, fe, 2, 0); // SamplesPerPixel
3132 writeUIntToStream(outStream, fe, 2, 0x116); writeUIntToStream(outStream, fe, 2, 4);
3133 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // RowsPerStrip
3134 writeUIntToStream(outStream, fe, 2, 0x117); writeUIntToStream(outStream, fe, 2, 4);
3135 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifSBC); // StripByteCounts
3136 writeUIntToStream(outStream, fe, 2, 0x11A); writeUIntToStream(outStream, fe, 2, 5);
3137 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, xResOff); // XResolution
3138 writeUIntToStream(outStream, fe, 2, 0x11B); writeUIntToStream(outStream, fe, 2, 5);
3139 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, yResOff); // YResolution
3140 writeUIntToStream(outStream, fe, 2, 0x11C); writeUIntToStream(outStream, fe, 2, 3);
3141 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPC); writeUIntToStream(outStream, fe, 2, 0); // PlanarConf
3142 writeUIntToStream(outStream, fe, 2, 0x128); writeUIntToStream(outStream, fe, 2, 3);
3143 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifResU); writeUIntToStream(outStream, fe, 2, 0); // ResolutionUnit
3144 if(haveXS) { // ExtraSamples
3145 if(haveManyXS) {
3146 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3147 writeUIntToStream(outStream, fe, 4, numXS); writeUIntToStream(outStream, fe, 4, xsOff);
3148 } else {
3149 if(markAlpha) { // is chan4alpha
3150 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3151 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1);
3152 } else {
3153 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3154 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 0);
3155 }
3156 }
3157 }
3158
3159 writeUIntToStream(outStream, fe, 2, 0x153);
3160 writeUIntToStream(outStream, fe, 2, 3); writeUIntToStream(outStream, fe, 4, 1);
3161 writeUIntToStream(outStream, fe, 2, sampFmt); writeUIntToStream(outStream, fe, 2, 0); // SampleFormat
3162
3163 writeUIntToStream(outStream, fe, 4, 0); // IFD END
3164 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // XResolutionData
3165 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // YResolutionData
3166 if(haveManyBPS) { // YResolutionData
3167 for(unsigned int i=0; i<tifSPP; i++)
3168 writeUIntToStream(outStream, fe, 2, tifBPS);
3169 }
3170 if(haveManyXS) // ExtraSamplesData (can't be RGBA is on xtra, not many)
3171 for(unsigned int i=0; i<numXS; i++)
3172 writeUIntToStream(outStream, fe, 4, 0);
3173 // Image data
3174 intCrdT x, y;
3175 bool yNat = !(pxFilter.isIntAxOrientationNaturalY());
3176 bool xNat = pxFilter.isIntAxOrientationNaturalX();
3177 for((yNat?y=0:y=(pxFilter.getNumPixY()-1)); (yNat?y<pxFilter.getNumPixY():y>=0); (yNat?y++:y--)) {
3178 for((xNat?x=0:x=(pxFilter.getNumPixX()-1)); (xNat?x<pxFilter.getNumPixX():x>=0); (xNat?x++:x--)) {
3179 typename rcConT::colorType aColor = pxFilter.getPxColorNC(x, y);
3180 for(int c=0; c<aColor.channelCount; c++) {
3181 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
3182 if (rcConT::colorType::chanIsInt)
3183 writeUIntToStream(outStream, fe, bytePerSmp, aChanValue); // Sample Data
3184 else
3185 outStream.write((const char *)&aChanValue, bytePerSmp); // Sample Data
3186 }
3187 }
3188 }
3189
3190 return 0;
3191 }
3192
3193////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3194 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3195 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3196 int
3198 intCrdT x1, intCrdT y1,
3199 intCrdT x2, intCrdT y2,
3200 int redChan, int greenChan, int blueChan, int alphaChan) {
3201 if(x1 > x2) // Get x1 < x2
3202 std::swap(x1, x2);
3203 if(y1 > y2) // Get y1 < y2
3204 std::swap(y1, y2);
3205
3206 if(x1 < 0) return 1; // Outside of canvas
3207 if(x2 >= numPixX) return 1; // Outside of canvas
3208 if(y1 < 0) return 1; // Outside of canvas
3209 if(y2 >= numPixY) return 1; // Outside of canvas
3210 if(x2 < x1) return 2; // Region too small (x direction)
3211 if(y2 < y1) return 3; // Region too small (y direction)
3212
3213 int bytesPerPix = (redChan<0?0:1) + (greenChan<0?0:1) + (blueChan<0?0:1) + (alphaChan<0?0:1);
3214 if(bytesPerPix < 1) return 4; // Exit if no channels selected
3215
3216 if(rasterData == 0) // Allocate space if rasterData==NULL. Caller must delete[]
3217 rasterData = (uint8_t *) new uint8_t[(y2-y1+1)*(x2-x1+1)*bytesPerPix];
3218
3219 if(rasterData == 0) return 5; // Exit if something went wrong with allocate...
3220
3221 uint8_t *curPixComp = (uint8_t *)rasterData;
3222 for(intCrdT y=y1; y<=y2; y++) {
3223 for(intCrdT x=x1; x<=x2; x++) {
3224 colorT aColor = getPxColorNC(x, y);
3225 if(redChan >= 0) curPixComp[redChan] = aColor.getChan_byte(aColor.bestRedChan());
3226 if(greenChan >= 0) curPixComp[greenChan] = aColor.getChan_byte(aColor.bestGreenChan());
3227 if(blueChan >= 0) curPixComp[blueChan] = aColor.getChan_byte(aColor.bestBlueChan());
3228 if(alphaChan >= 0) curPixComp[alphaChan] = aColor.getChan_byte(aColor.bestAlphaChan());
3229 curPixComp += bytesPerPix;
3230 } /* end for x */
3231 } /* end for y */
3232
3233 return 0;
3234 }
3235
3236////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3237 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3238 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3239 inline intCrdT
3242 return static_cast<intCrdT>((static_cast<fltCrdT>(x) - minRealX) / pixWidX);
3243 else
3244 return static_cast<intCrdT>((maxRealX - static_cast<fltCrdT>(x)) / pixWidX);
3245 }
3246
3247////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3248 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3249 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3250 inline intCrdT
3253 return static_cast<intCrdT>((static_cast<fltCrdT>(y) - minRealY) / pixWidY);
3254 else
3255 return static_cast<intCrdT>((maxRealY - static_cast<fltCrdT>(y)) / pixWidY);
3256 }
3257
3258////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3259 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3260 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3261 inline fltCrdT
3264 return static_cast<fltCrdT>(x) * pixWidX + minRealX;
3265 else
3266 return maxRealX - static_cast<fltCrdT>(x) * pixWidX;
3267 }
3268
3269////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3270 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3271 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3272 inline fltCrdT
3275 return static_cast<fltCrdT>(y) * pixWidY + minRealY;
3276 else
3277 return maxRealY - static_cast<fltCrdT>(y) * pixWidY;
3278 }
3279
3280////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3281 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3282 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3283 colorT*
3285 colorT *pixelsCopy = new colorT[numPixX * numPixY];
3286 for(intCrdT y=0; y<numPixY; y++)
3287 for(intCrdT x=0; x<numPixX; x++)
3288 pixelsCopy[numPixX * y + x] = getPxColorNC(x, y);
3289 }
3290
3291////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3292 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3293 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3294 inline colorT
3296 if(isOnCanvas(x, y)) [[likely]]
3297 return pixels[numPixX * y + x];
3298 else
3299 return colorT().setToBlack();
3300 }
3301
3302////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3303 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3304 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3305 inline colorT
3307 switch (interpMethod) {
3313 default : return colorT("green"); // Just in case I add an enum value, and forget to update this switch.
3314 }
3315 }
3316
3317////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3318 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3319 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3320 colorT
3322 double x1 = std::floor(x);
3323 double y1 = std::floor(y);
3324 double x2 = std::ceil(x);
3325 double y2 = std::ceil(y);
3326
3327 intCrdT x1i = static_cast<intCrdT>(x1);
3328 intCrdT y1i = static_cast<intCrdT>(y1);
3329 intCrdT x2i = static_cast<intCrdT>(x2);
3330 intCrdT y2i = static_cast<intCrdT>(y2);
3331
3332 colorT cF;
3333
3334 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3335 double eps = 0.00001;
3336 double xD21 = x2 - x1;
3337 double yD21 = y2 - y1;
3338 double wH = 1.0;
3339 if (mjr::math::fc::not_near_zero(xD21, eps))
3340 wH = (x - x1) / xD21;
3341 double wV = 1.0;
3342 if (mjr::math::fc::not_near_zero(yD21, eps))
3343 wV = (y - y1) / yD21;
3344
3345 colorT c1;
3346 colorT c2;
3347 c1.linearInterpolate(wH, getPxColorRefNC(x1i, y1i), getPxColorRefNC(x2i, y1i));
3348 c2.linearInterpolate(wH, getPxColorRefNC(x1i, y2i), getPxColorRefNC(x2i, y2i));
3349 cF.linearInterpolate(wV, c1, c2);
3350 } else {
3351 cF.setToBlack();
3352 }
3353 return cF;
3354 }
3355
3356////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3357 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3358 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3359 inline colorT
3361 return getPxColor(static_cast<intCrdT>(std::trunc(x)), static_cast<intCrdT>(std::trunc(y)));
3362 }
3363
3364////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3365 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3366 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3367 inline colorT
3369 return getPxColor(static_cast<intCrdT>(std::round(x)), static_cast<intCrdT>(std::round(y)));
3370 }
3371
3372////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3373 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3374 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3375 inline colorT
3377 intCrdT xi = static_cast<intCrdT>(std::round(x));
3378 intCrdT yi = static_cast<intCrdT>(std::round(y));
3379 colorT newColor;
3380 for(int chan=0; chan<colorT::channelCount; chan++) {
3381 colorChanArithSDPType newChanValue = 0;
3382 for(intCrdT ydi=-1; ydi<=1; ydi++) {
3383 intCrdT icY = yi + ydi;
3384 for(intCrdT xdi=-1; xdi<=1; xdi++) {
3385 intCrdT icX = xi + xdi;
3386 if (!(isCliped(icX, icY))) {
3387 newChanValue += getPxColor(icX, icY).getChan(chan);
3388 }
3389 }
3390 }
3391 newColor.setChan(chan, static_cast<colorChanType>(newChanValue / 9));
3392 }
3393 return newColor;
3394 }
3395
3396////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3397 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3398 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3399 colorT
3401 double x1 = std::floor(x);
3402 double y1 = std::floor(y);
3403 double x2 = std::ceil(x);
3404 double y2 = std::ceil(y);
3405
3406 intCrdT x1i = static_cast<intCrdT>(x1);
3407 intCrdT y1i = static_cast<intCrdT>(y1);
3408 intCrdT x2i = static_cast<intCrdT>(x2);
3409 intCrdT y2i = static_cast<intCrdT>(y2);
3410
3411 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3412
3413 colorT c1 = pixels[numPixX * y1i + x1i];
3414 c1.tfrmMean(pixels[numPixX * y1i + x2i]);
3415
3416 colorT c2 = pixels[numPixX * y2i + x1i];
3417 c2.tfrmMean(pixels[numPixX * y2i + x2i]);
3418
3419 c1.tfrmMean(c2);
3420
3421 return c1;
3422 } else {
3423 return colorT().setToBlack();
3424 }
3425 }
3426
3427// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3428// template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3429// requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3430// void
3431// ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts) {
3432// moveTo(x2, y2); // Do this first
3433// intCrdT x, y;
3434// if(y1 == y2) { // slope = 0
3435// if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
3436// return;
3437// if(x1 > x2) // . Fix point ordering
3438// std::swap(x1, x2);
3439// if(x1 < 0) // . Clip left
3440// x1 = 0;
3441// if(x2 >= numPixX) // . Clip right
3442// x2 = numPixX - 1;
3443// //drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
3444// return; // mark edge
3445// } else if(x1 == x2) { // slope = infinity
3446// if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
3447// return;
3448// if(y1 > y2) // . Fix point ordering
3449// std::swap(y1, y2);
3450// if(y1 < 0) // . Clip top
3451// y1 = 0;
3452// if(y2 >= numPixY) // . Clip bottom
3453// y2 = numPixY - 1;
3454// //drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
3455// for(y=y1; y<=y2; y++) pts[y] = x1; // mark edge
3456// } else { // Slope is not infinity or 0...
3457// int dx, dy;
3458// if(x1 > x2) { // . Fix point ordering
3459// std::swap(x1, x2);
3460// std::swap(y1, y2);
3461// }
3462// dx = x2 - x1; // . Compute the slope
3463// dy = y2 - y1;
3464// if(dx == dy) { // . Slope = 1
3465// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
3466// return;
3467// if(x1 < 0) { // .. Clip left
3468// y1 = y1 - x1;
3469// x1 = 0;
3470// }
3471// if(y1 < 0) { // .. Clip top
3472// x1 = x1 - y1;
3473// y1 = 0;
3474// }
3475// if(x2 >= numPixX) { // .. Clip right
3476// y2 = y2 - (x2 - numPixX) - 1;
3477// x2 = numPixX - 1;
3478// }
3479// if(y2 >= numPixY) { // .. Clip bottom
3480// x2 = x2 - (y2 - numPixY) - 1;
3481// y2 = numPixY - 1;
3482// }
3483// for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
3484// //drawPointNC(x, y, color);
3485// pts[y] = x; // mark edge
3486// } else if(dx == -dy) { // . Slope = -1
3487// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
3488// return;
3489// if(x1 < 0) { // .. Clip left
3490// y1 = y1 + x1;
3491// x1 = 0;
3492// }
3493// if(x2 >= numPixX) { // .. Clip right
3494// y2 = y2 + (x2 - (numPixX - 1));
3495// x2 = numPixX - 1;
3496// }
3497// if(y2 < 0) { // .. Clip top
3498// x2 = x2 + y2;
3499// y2 = 0;
3500// }
3501// if(y1 >= numPixY) { // .. Clip bottom
3502// x1 = x1 + (y1 - (numPixY - 1));
3503// y1 = numPixY - 1;
3504// }
3505// for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
3506// //drawPointNC(x, y, color);
3507// pts[y] = x; // mark edge
3508// } else { // . Slope != 1, -1, 0, \infinity
3509// int s, dx2, dy2;
3510// dx2 = 2*dx;
3511// dy2 = 2*dy;
3512// if(dy > 0) { // .. Positive Slope
3513// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
3514// return;
3515// if(x1 < 0) { // ... Clip left
3516// y1 = (int)(1.0*y1-x1*dy/dx);
3517// x1 = 0;
3518// }
3519// if(y1 < 0) { // ... Clip top
3520// x1 = (int)(1.0*x1-y1*dx/dy);
3521// y1 = 0;
3522// }
3523// if(x2 >= numPixX) { // ... Clip right
3524// y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
3525// x2 = numPixX - 1;
3526// }
3527// if(y2 >= numPixY) { // ... Clip bottom
3528// x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
3529// y2 = numPixY - 1;
3530// }
3531// if(dx > dy) { // ... 0 < Slope < 1
3532// s = dy2 - dx;
3533// x=x1;
3534// y=y1;
3535// while(x<=x2) { // .... Draw Line
3536// //drawPoint(x, y, color);
3537// pts[y] = x; // mark edge
3538// if(s < 0) {
3539// s += dy2;
3540// } else {
3541// y++;
3542// s += dy2 - dx2;
3543// }
3544// x++;
3545// }
3546// } else { // ... 1 < Slope < infinity
3547// s = dy - dx2;
3548// x=x1;
3549// y=y1;
3550// while(y<=y2) { // .... Draw Line
3551// //drawPoint(x, y, color);
3552// pts[y] = x; // mark edge
3553// if(s > 0) {
3554// s -= dx2;
3555// } else {
3556// x++;
3557// s += dy2 - dx2;
3558// }
3559// y++;
3560// }
3561// }
3562// } else { // .. Negative Slope
3563// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
3564// return;
3565// if(x1 < 0) { // ... Clip left
3566// y1 = (int)(1.0*y1-x1*dy/dx);
3567// x1 = 0;
3568// }
3569// if(y2 < 0) { // ... Clip top
3570// x2 = (int)(1.0*x2-y2*dx/dy);
3571// y2 = 0;
3572// }
3573// if(x2 >= numPixX) { // ... Clip right
3574// y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
3575// x2 = numPixX - 1;
3576// }
3577// if(y1 >= numPixY) { // ... Clip bottom
3578// x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
3579// y1 = numPixY - 1;
3580// }
3581// if(dx > -dy) { // ... 0 > Slope > -infinity
3582// s = dy2 + dx;
3583// x=x1;
3584// y=y1;
3585// while(x<=x2) { // .... Draw Line
3586// //drawPoint(x, y, color);
3587// pts[y] = x; // mark edge
3588// if(s > 0) {
3589// s += dy2;
3590// } else {
3591// y--;
3592// s += dy2 + dx2;
3593// }
3594// x++;
3595// }
3596// } else { // ... -1 > Slope > -inf
3597// s = dy + dx2;
3598// x=x1;
3599// y=y1;
3600// while(y>=y2) { // .... Draw Line
3601// //drawPoint(x, y, color);
3602// pts[y] = x; // mark edge
3603// if(s < 0) {
3604// s += dx2;
3605// } else {
3606// x++;
3607// s += dy2 + dx2;
3608// }
3609// y--;
3610// }
3611// }
3612// }
3613// }
3614// }
3615// }
3616
3617////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3618 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3619 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3620 inline void
3621 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin) {
3622 // This code is essentially the line drawing code with some simplifications.
3623 intCrdT x, y;
3624 if(x1 == x2) { // slope = infinity
3625 if(y1 > y2) // Fix point ordering
3626 std::swap(y1, y2);
3627 for(y=y1; y<=y2; y++) // Draw PIxels: drawVertLineNC(y1, y2, x1, color);
3628 pts[y]=x1; // set bound
3629 } else { // Slope is not infinity or 0...
3630 int dx, dy;
3631 if(x1 > x2) { // Fix point ordering
3632 std::swap(x1, x2);
3633 std::swap(y1, y2);
3634 }
3635 dx = x2 - x1; // Compute the slope
3636 dy = y2 - y1;
3637 if(dx == dy) { // Slope = 1
3638 for(x=x1,y=y1;x<=x2;y++,x++) // Draw Pixels
3639 pts[y]=x; // set bound
3640 } else if(dx == -dy) { // Slope = -1
3641 for(x=x1,y=y1;x<=x2;y--,x++) // Draw Pixels
3642 pts[y]=x; // set bound
3643 } else { // Slope != 1, -1, 0, \infinity
3644 int s, dx2, dy2;
3645 dx2 = 2*dx;
3646 dy2 = 2*dy;
3647 if(dy > 0) { // Positive Slope
3648 if(dx > dy) { // 0 < Slope < 1
3649 if (findMin) {
3650 s = dy2 - dx;
3651 x=x1;
3652 y=y1;
3653 intCrdT lastY=y-1;
3654 while(x<=x2) { // Draw Line
3655 if (y != lastY)
3656 pts[y]=x; // set bound
3657 lastY = y;
3658 if(s < 0) {
3659 s += dy2;
3660 } else {
3661 y++;
3662 s += dy2 - dx2;
3663 }
3664 x++;
3665 }
3666 } else { // works.
3667 s = dy2 - dx;
3668 x=x1;
3669 y=y1;
3670 while(x<=x2) { // Draw Line
3671 pts[y]=x; // set bound
3672 if(s < 0) {
3673 s += dy2;
3674 } else {
3675 y++;
3676 s += dy2 - dx2;
3677 }
3678 x++;
3679 }
3680 }
3681 } else { // 1 < Slope < infinity
3682 s = dy - dx2;
3683 x=x1;
3684 y=y1;
3685 while(y<=y2) { // Draw Line
3686 pts[y]=x; // set bound
3687 if(s > 0) {
3688 s -= dx2;
3689 } else {
3690 x++;
3691 s += dy2 - dx2;
3692 }
3693 y++;
3694 }
3695 }
3696 } else { // Negative Slope
3697 if(dx > -dy) { // 0 > Slope > -1
3698 if (findMin) {
3699 s = dy2 + dx;
3700 x=x1;
3701 y=y1;
3702 intCrdT lastY=y-1;
3703 while(x<=x2) { // Draw Line
3704 if (y != lastY)
3705 pts[y]=x; // set bound
3706 lastY = y;
3707 if(s > 0) {
3708 s += dy2;
3709 } else {
3710 y--;
3711 s += dy2 + dx2;
3712 }
3713 x++;
3714 }
3715 } else {
3716 s = dy2 + dx;
3717 x=x1;
3718 y=y1;
3719 while(x<=x2) { // Draw Line
3720 pts[y]=x; // set bound
3721 if(s > 0) {
3722 s += dy2;
3723 } else {
3724 y--;
3725 s += dy2 + dx2;
3726 }
3727 x++;
3728 }
3729 }
3730 } else { // -1 > Slope > -inf
3731 s = dy + dx2;
3732 x=x1;
3733 y=y1;
3734 while(y>=y2) { // Draw Line
3735 pts[y]=x; // set bound
3736 if(s < 0) {
3737 s += dx2;
3738 } else {
3739 x++;
3740 s += dy2 + dx2;
3741 }
3742 y--;
3743 }
3744 }
3745 }
3746 }
3747 }
3748 }
3749
3750////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3751 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3752 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3753 inline void
3754 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3755 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color, color, color, true);
3756 }
3757
3758////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3759 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3760 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3761 inline void
3763 intCrdT x2, intCrdT y2,
3764 intCrdT x3, intCrdT y3,
3765 colorArgType color1, colorArgType color2, colorArgType color3) {
3766 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color1, color2, color3, false);
3767 }
3768
3769////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3770 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3771 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3772 void
3774 intCrdT x2, intCrdT y2,
3775 intCrdT x3, intCrdT y3,
3776 colorT c1, colorT c2, colorT c3, bool solid) { // Not colorArgType because of std::swap
3777 static intCrdT *minPts, *maxPts;
3778 static intCrdT numPts;
3779
3780 if( isCliped(x1, y1) || isCliped(x2, y2) || isCliped(x3, y3))
3781 return;
3782
3783 ///////////////////////////////////////////////////////////////////////////////////
3784 // Check our work space, and allocate/reallocate as required.
3785 if(minPts == NULL) { // First time in function -- allocate
3786 minPts = new intCrdT[numPixY];
3787 maxPts = new intCrdT[numPixY];
3788 numPts = numPixY;
3789 } else { // Not our first time! We have a work space.
3790 if(numPts != numPixY) { // Work space is wrong size -- reallocate
3791 delete[] minPts;
3792 delete[] maxPts;
3793 minPts = new intCrdT[numPixY];
3794 maxPts = new intCrdT[numPixY];
3795 numPts = numPixY;
3796 }
3797 }
3798
3799 ///////////////////////////////////////////////////////////////////////////////////
3800 if (!(solid) && ((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) == 0))
3801 return;
3802
3803 ///////////////////////////////////////////////////////////////////////////////////
3804 // Sort (x1,y1), (x2,y2), (x3,y3) so that y1 >= y2, y3 and y3 <= y2, y1
3805 if(y1 > y2) { // top != 2 && bot != 1
3806 if(y1 > y3) { // top != 3 y1>y2 y1>y3 y2>y3 top bot
3807 if(y2 > y3) { // bot != 2 . . . . .
3808 // T T T 1 3 NOP
3809 } else { // bot != 3 . . . . .
3810 std::swap(y2,y3); // T T F 1 2 SWAP(2,3)
3811 std::swap(x2,x3); // . . . . .
3812 std::swap(c2,c3); // . . . . .
3813 } // . . . . .
3814 } else { // top != 1 . . . . .
3815 std::swap(y1,y3); // T F U 3 2 SWAP(1,3) SWAP(2,3)
3816 std::swap(y2,y3); // . . . . .
3817 std::swap(x1,x3); // . . . . .
3818 std::swap(x2,x3); // . . . . .
3819 if(!solid) { // . . . . .
3820 std::swap(c1,c3); // . . . . .
3821 std::swap(c2,c3); // . . . . .
3822 } // . . . . .
3823 } // . . . . .
3824 } else { // top != 1 . . . . .
3825 if(y2 > y3) { // top != 3 && bot != 2 . . . . .
3826 if(y1 > y3) { // bot != 1 . . . . .
3827 std::swap(y1,y2); // F T T 2 3 SWAP(1,2)
3828 std::swap(x1,x2); // . . . . .
3829 std::swap(c1,c2); // . . . . .
3830 } else { // bot != 3 . . . . .
3831 std::swap(y1,y2); // F F T 2 1 SWAP(1,2) SWAP(2,3)
3832 std::swap(y2,y3); // . . . . .
3833 std::swap(x1,x2); // . . . . .
3834 std::swap(x2,x3); // . . . . .
3835 if(!solid) { // . . . . .
3836 std::swap(c1,c2); // . . . . .
3837 std::swap(c2,c3); // . . . . .
3838 } // . . . . .
3839 } // . . . . .
3840 } else { // top != 2 && bot != 3 . . . . .
3841 std::swap(y1,y3); // F U F 3 1 SWAP(1,3)
3842 std::swap(x1,x3); // . . . . .
3843 std::swap(c1,c3); // . . . . .
3844 }
3845 }
3846
3847 ///////////////////////////////////////////////////////////////////////////////////////
3848 /* cA y1==y2 point 1,2,3 */
3849 /* cB-cG y1==y2 h line 1,2---3 3---1,2 1,3---2 2---1,3 2,3---1 1---2,3 */
3850 /* cH-cJ y1==y2 v line 1,2 1,2 1,2 */
3851 /* \ | / */
3852 /* 3 3 3 */
3853 /* cK-cL y1==y2 tri 1---2 2---1 */
3854 /* \ / \ / */
3855 /* 3 3 */
3856 /* cM-cO y2=y3 v line 1 1 1 */
3857 /* \ | / */
3858 /* 2,3 2,3 2,3 */
3859 /* cP-cQ y2=y3 tri 1 1 */
3860 /* / \ / \ */
3861 /* 2---3 3---2 */
3862 /* cR-cS General 1 1 Note x1 need not equal x3 in these cases! */
3863 /* |\ /| It is just difficult to draw a case with */
3864 /* | 2 2 | x1 != x3 with tiny ASCII art... */
3865 /* |/ \| */
3866 /* 3 3 */
3867 ///////////////////////////////////////////////////////////////////////////////////////
3868
3869 if(y1==y3) { // cA-cG
3870 minPts[y1] = mjr::math::odr::min3(x1, x2, x3); //
3871 maxPts[y1] = mjr::math::odr::max3(x1, x2, x3); //
3872 } else { // cH-cS
3873 if(y1==y2) { // cH-cL
3874 if(x1==x2) { // cH-cJ
3875 triangleEdger(x1, y1, x3, y3, minPts, true); //
3876 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3877 } else if(x1<x2) { // cK
3878 triangleEdger(x1, y1, x3, y3, minPts, true); //
3879 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3880 } else { // cJ
3881 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3882 triangleEdger(x2, y2, x3, y3, minPts, true); //
3883 } //
3884 } else if(y2==y3) { // cM-cQ
3885 if(x2==x3) { // cM-cO
3886 triangleEdger(x1, y1, x3, y3, minPts, true); //
3887 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3888 } else if(x2<x3) { // cP
3889 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3890 triangleEdger(x2, y2, x1, y1, minPts, true); //
3891 } else { // cQ
3892 triangleEdger(x1, y1, x3, y3, minPts, true); //
3893 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3894 } //
3895 } else { // cR-cS
3896 double xOt = (x1*y3+x3*y2-x1*y2-x3*y1); //
3897 double xOb = (y3-y1); //
3898 if(xOt/xOb < x2) { // cR
3899 triangleEdger(x1, y1, x3, y3, minPts, true); //
3900 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3901 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3902 } else { // cS
3903 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3904 triangleEdger(x2, y2, x1, y1, minPts, true); //
3905 triangleEdger(x2, y2, x3, y3, minPts, true); //
3906 } //
3907 } //
3908 } //
3909
3910 ///////////////////////////////////////////////////////////////////////////////////
3911 // Fill between the left and right bits.
3912 if(solid) {
3913 for(intCrdT y=y3; y<=y1; y++)
3914 drawLine(minPts[y], y, maxPts[y], y, c1);
3915 } else {
3916 for(intCrdT y=y3; y<=y1; y++)
3917 for(intCrdT x=minPts[y]; x<=maxPts[y]; x++) {
3918 /* Performance & Correctness: This code seems very poorly optimized. Especially the computation of w3 instead of simply using 1-w1-w2, and the
3919 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
3920 computations. Sometimes, for example, the coordinates of a fill point won't, technically, be in the triangle. Or the sum of the areas
3921 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
3922 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
3923 consistency and accuracy on edges. The repeated common expressions are optimized by the compiler. This branch is roughly 15x slower than the
3924 solid branch above. */
3925 colorChanArithFltType w1 = std::abs(static_cast<colorChanArithFltType>( x*(y2 - y3) + x2*(y3 - y) + x3*(y - y2)));
3926 colorChanArithFltType w2 = std::abs(static_cast<colorChanArithFltType>(x1*(y - y3) + x*(y3 - y1) + x3*(y1 - y)));
3927 colorChanArithFltType w3 = std::abs(static_cast<colorChanArithFltType>(x1*(y2 - y) + x2*(y - y1) + x*(y1 - y2)));
3928 drawPointNC(x, y, colorT().wMean(w1/(w1+w2+w3), w2/(w1+w2+w3), w3/(w1+w2+w3), c1, c2, c3));
3929 }
3930 }
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 inline void
3938 drawPLCurve(numPoints, x, y, dfltColor);
3939 }
3940
3941////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3942 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3943 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3944 inline void
3946 for(int i=0; i<numPoints-1; i++)
3947 drawLine(real2intX(x[i]), real2intY(y[i]), real2intX(x[i+1]), real2intY(y[i+1]), color);
3948 }
3949
3950////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3951 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3952 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3953 inline void
3955 drawPLCurve(numPoints, x, y, dfltColor);
3956 }
3957
3958////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3959 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3960 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3961 inline void
3963 for(int i=0; i<numPoints-1; i++)
3964 drawLine(x[i], y[i], x[i+1], y[i+1], color);
3965 }
3966
3967////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3968 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3969 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3970 inline void
3972 for(int i=0; i<numPoints-1; i++)
3973 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3974 }
3975
3976////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3977 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3978 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3979 inline void
3981 for(int i=0; i<numPoints-1; i++)
3982 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3983 }
3984
3985////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3986 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3987 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3988 inline void
3990 drawPLCurve(numPoints, thePoints, dfltColor);
3991 }
3992
3993////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3994 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3995 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3996 inline void
3998 drawPLCurve(numPoints, thePoints, dfltColor);
3999 }
4000
4001////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4002 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4003 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4004 inline void
4005 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
4006 drawLine(x1, y1, x2, y2, color);
4007 drawLine(x2, y2, x3, y3, color);
4008 drawLine(x3, y3, x1, y1, color);
4009 }
4010
4011////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4012 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4013 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4014 void
4015 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
4016 int x = 0;
4017 int y = radiusX;
4018 int d = 1 - radiusX;
4019 int deltaE = 3;
4020 int deltaSE = -2 * radiusX + 5;
4021
4022 drawPoint( x+centerX, y+centerY, color);
4023 drawPoint( x+centerX,-y+centerY, color);
4024 drawPoint(-x+centerX, y+centerY, color);
4025 drawPoint(-x+centerX,-y+centerY, color);
4026 drawPoint( y+centerX, x+centerY, color);
4027 drawPoint( y+centerX,-x+centerY, color);
4028 drawPoint(-y+centerX, x+centerY, color);
4029 drawPoint(-y+centerX,-x+centerY, color);
4030
4031 while(y>x) {
4032 if(d<0) {
4033 d += deltaE;
4034 deltaE += 2;
4035 deltaSE += 2;
4036 } else {
4037 d += deltaSE;
4038 deltaE += 2;
4039 deltaSE += 4;
4040 y--;
4041 }
4042 x++;
4043 drawPoint( x+centerX, y+centerY, color);
4044 drawPoint( x+centerX,-y+centerY, color);
4045 drawPoint(-x+centerX, y+centerY, color);
4046 drawPoint(-x+centerX,-y+centerY, color);
4047 drawPoint( y+centerX, x+centerY, color);
4048 drawPoint( y+centerX,-x+centerY, color);
4049 drawPoint(-y+centerX, x+centerY, color);
4050 drawPoint(-y+centerX,-x+centerY, color);
4051 }
4052
4053 }
4054
4055////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4056 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4057 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4058 void
4059 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
4060 int minXY;
4061 int x = 0;
4062 int y = radiusX;
4063 int d = 1 - radiusX;
4064 int deltaE = 3;
4065 int deltaSE = -2 * radiusX + 5;
4066
4067 if(x > y)
4068 minXY = y;
4069 else
4070 minXY = x;
4071 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
4072 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
4073 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
4074 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
4075 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
4076 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
4077 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4078 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4079
4080 while(y>x) {
4081 if(d<0) {
4082 d += deltaE;
4083 deltaE += 2;
4084 deltaSE += 2;
4085 } else {
4086 d += deltaSE;
4087 deltaE += 2;
4088 deltaSE += 4;
4089 y--;
4090 }
4091 x++;
4092
4093 if(x > y)
4094 minXY = y;
4095 else
4096 minXY = x;
4097 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
4098 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
4099 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
4100 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
4101 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
4102 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
4103 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4104 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4105 }
4106 }
4107
4108////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4109 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4110 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4111 void
4112 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
4113 if(x1 > x2) // Get x1 < x2
4114 std::swap(x1, x2);
4115 if(y1 > y2) // Get y1 < y2
4116 std::swap(y1, y2);
4117 if( (y1 < numPixY) && (x1 < numPixX) && (y2 >= 0) && (x2 >= 0) ) { // Part of rect visible
4118 int noTop, noBottom, noLeft, noRight;
4119 if((noTop=(y1 < 0)))
4120 y1 = 0;
4121 if((noLeft=(x1 < 0)))
4122 x1 = 0;
4123 if((noBottom=(y2 >= numPixY)))
4124 y2 = numPixY - 1;
4125 if((noRight=(x2 >= numPixX)))
4126 x2 = numPixX - 1;
4127 // Draw top/bottom/left/right lines
4128 if(!noLeft) // Have left
4129 drawVertLineNC(y1, y2, x1, color);
4130 if(!noRight) // Have Right
4131 drawVertLineNC(y1, y2, x2, color);
4132 if(!noTop) // Have top
4133 drawHorzLineNC(x1, x2, y1, color);
4134 if(!noBottom) // Have bottom
4135 drawHorzLineNC(x1, x2, y2, color);
4136 }
4137 }
4138
4139////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4140 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4141 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4142 inline void
4144 if(x1 > x2) // Get x1 < x2
4145 std::swap(x1, x2);
4146 if(y1 > y2) // Get y1 < y2
4147 std::swap(y1, y2);
4148 // Clip
4149 if( (y1 >= numPixY) || (x1 >= numPixX) || (y2 < 0) || (x2 < 0) )
4150 return;
4151 if(y1 < 0)
4152 y1 = 0;
4153 if(x1 < 0)
4154 x1 = 0;
4155 if(y2 >= numPixY)
4156 y2 = numPixY - 1;
4157 if(x2 >= numPixX)
4158 x2 = numPixX - 1;
4159 for(intCrdT y=y1;y<=y2;y++)
4160 drawHorzLineNC(x1, x2, y, color);
4161 }
4162
4163////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4164 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4165 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4166 inline void
4168 if constexpr (enableDrawModes)
4169 switch(drawMode) {
4170 case drawModeType::SET: getPxColorRefNC(x, y).copy(color); break;
4171 case drawModeType::XOR: getPxColorRefNC(x, y).tfrmXor(color); break;
4172 case drawModeType::ADDCLAMP: getPxColorRefNC(x, y).tfrmAddClamp(color); break;
4173 case drawModeType::AND: getPxColorRefNC(x, y).tfrmAnd(color); break;
4174 case drawModeType::OR: getPxColorRefNC(x, y).tfrmOr(color); break;
4175 case drawModeType::DIFFCLAMP: getPxColorRefNC(x, y).tfrmDiffClamp(color); break;
4176 case drawModeType::MULTCLAMP: getPxColorRefNC(x, y).tfrmMultClamp(color); break;
4177 }
4178 else
4179 getPxColorRefNC(x, y).copy(color);
4180 }
4181
4182////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4183 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4184 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4185 void
4187 if (xfactor > 1) {
4188 intCrdT new_numPixX_p = xfactor*numPixX;
4189 intCrdT new_numPixY_p = xfactor*numPixY;
4190 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4191 for(intCrdT y=0, y1=0; y<numPixY; y++) {
4192 for(intCrdT x=0, x1=0; x<numPixX; x++) {
4193 for(int i=0; i<xfactor; i++) {
4194 for(int j=0; j<xfactor; j++) {
4195 new_pixels[new_numPixX_p * y1 + x1] = getPxColor(x, y);
4196 x1++;
4197 }
4198 x1-=xfactor;
4199 y1++;
4200 }
4201 x1+=xfactor;
4202 y1-=xfactor;
4203 }
4204 y1+=xfactor;
4205 }
4206 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4207 }
4208 }
4209
4210////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4211 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4212 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4213 void
4215 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4216 intCrdT new_numPixX_p = numPixX/xfactor;
4217 intCrdT new_numPixY_p = numPixY/xfactor;
4218 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4219 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4220 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor)
4221 new_pixels[new_numPixX_p * y + x] = getPxColor(x1, y1);
4222 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4223 }
4224 }
4225
4226////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4227 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4228 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4229 void
4231 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4232 intCrdT new_numPixX_p = numPixX/xfactor;
4233 intCrdT new_numPixY_p = numPixY/xfactor;
4234 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4235 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4236 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4237 std::vector<colorChanArithSDPType> sums(colorT::channelCount, static_cast<colorChanArithSDPType>(0));
4238 for(int j=0; j<xfactor; j++)
4239 for(int i=0; i<xfactor; i++)
4240 for(int c=0; c<colorT::channelCount; c++)
4241 sums[c] += getPxColor(x1+i, y1+j).getChan(c);
4242 colorT aColor;
4243 for(int c=0; c<colorT::channelCount; c++)
4244 aColor.setChan(c, static_cast<colorChanType>(sums[c] / (xfactor*xfactor)));
4245 new_pixels[new_numPixX_p * y + x] = aColor;
4246 }
4247 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4248 }
4249 }
4250
4251////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4252 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4253 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4254 void
4256 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4257 intCrdT new_numPixX_p = numPixX/xfactor;
4258 intCrdT new_numPixY_p = numPixY/xfactor;
4259 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4260 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4261 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4262 colorT maxColor = getPxColor(xfactor*x, xfactor*y);
4263 for(int yi=0; yi<xfactor; yi++)
4264 for(int xi=0; xi<xfactor; xi++)
4265 maxColor.tfrmMaxI(getPxColor(xfactor*x+xi, xfactor*y+yi));
4266 new_pixels[new_numPixX_p * y + x] = maxColor;
4267 }
4268 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4269 }
4270 }
4271
4272////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4273 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4274 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4275 void
4277 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4278 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4279 kernel[kSize * yi + xi] = exp(-(xis*xis+yis*yis)/(2*sd*sd))/(sd*sd*2*std::numbers::pi);
4280 double divisor = 0;
4281 for(int i=0; i<(kSize*kSize); i++)
4282 divisor += kernel[i];
4283 for(int i=0; i<(kSize*kSize); i++)
4284 kernel[i] /= divisor;
4285 }
4286
4287////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4288 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4289 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4290 void
4292 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4293 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4294 kernel[kSize * yi + xi] = 1.0/(kSize*kSize);
4295 }
4296
4297////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4298 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4299 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4300 void
4301 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::convolution(double *kernel, int kWide, int kTall, double divisor) {
4302 colorT *new_pixels = new colorT[numPixX * numPixY];
4303 // Divisor is invalid, so we compute one to use
4304 if (mjr::math::fc::near_zero(divisor, 0.0001)) {
4305 divisor = 0.0;
4306 for(int i=0; i<(kWide*kTall); i++)
4307 divisor += kernel[i];
4308 }
4309 // Apply filter
4310 double tmp[colorT::channelCount];
4311 for(intCrdT y=0; y<numPixY; y++) {
4312 for(intCrdT x=0; x<numPixX; x++) {
4313 colorT newColor;
4314 for(int chan=0; chan<colorT::channelCount; chan++)
4315 tmp[chan] = 0.0;
4316 for(int yi=0, yis=-(kTall/2); yi<kTall; yi++, yis++) {
4317 intCrdT icY = y + yis;
4318 for(int xi=0,xis=-(kWide/2); xi<kWide; xi++, xis++) {
4319 intCrdT icX = x + xis;
4320 if (!(isCliped(icX, icY))) {
4321 for(int chan=0; chan<colorT::channelCount; chan++)
4322 tmp[chan] += static_cast<double>(getPxColor(icX, icY).getChan(chan)) * kernel[kWide * yi + xi];
4323 }
4324 }
4325 }
4326 for(int chan=0; chan<colorT::channelCount; chan++)
4327 new_pixels[numPixX * y + x].setChan(chan, static_cast<colorChanType>(tmp[chan] / divisor));
4328 }
4329 }
4330 rePointPixels(new_pixels, numPixX, numPixY);
4331 }
4332
4333////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4334 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4335 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4336 inline void
4338 convolution(kernel, kSize, kSize, divisor);
4339 }
4340////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4341 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4342 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4343 inline void
4345 convolution(kernel, kSize, kSize, 1.0);
4346 }
4347
4348////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4349 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4350 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4351 void
4352 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor) {
4353 intCrdT x1, y1;
4354 int actionIsMoveTo;
4355
4356 if( (glyphNum < 0) || (glyphNum > 3934) )
4357 glyphNum = 699;
4358
4359 actionIsMoveTo=1;
4360 for(int i=0; i<(mjr::hershey::chars[glyphNum]).numComp; i++) {
4361 if((mjr::hershey::chars[glyphNum]).components[2*i] == ' ') {
4362 actionIsMoveTo = 1;
4363 } else {
4365 x1 = static_cast<intCrdT>(magX * ((mjr::hershey::chars[glyphNum]).components[2*i] - 'R'));
4366 else
4367 x1 = static_cast<intCrdT>(magX * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i]));
4368
4370 y1 = static_cast<intCrdT>(magY * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i+1]));
4371 else
4372 y1 = static_cast<intCrdT>(magY * ((mjr::hershey::chars[glyphNum]).components[2*i+1] - 'R'));
4373
4374 if(actionIsMoveTo) {
4375 moveTo(x1+x, y1+y);
4376 actionIsMoveTo = 0;
4377 } else {
4378 drawLine(x1+x, y1+y, aColor);
4379 }
4380 }
4381 }
4382 }
4383
4384////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4385 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4386 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4387 inline void
4388 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc) {
4389 for(auto &c : aString) {
4390 int glyphNum = 0;
4391 if((c>=32) && (c<=126))
4392 glyphNum = mjr::hershey::ascii2hershey[(int)aFont][c-32];
4393 drawHersheyGlyph(glyphNum, x, y, cex, cex, aColor);
4394 x+=static_cast<intCrdT>(spc*cex);
4395 }
4396 }
4397
4398////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4399 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4400 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4401 inline void
4403 mjr::hershey::font aFont,
4404 intCrdT x, intCrdT y,
4405 colorArgType stringColor, colorArgType boxColor,
4406 double cex, intCrdT spc) {
4407 drawFillRectangle(static_cast<intCrdT>(x-spc*cex),
4408 static_cast<intCrdT>(y-spc*cex),
4409 static_cast<intCrdT>(x+spc*cex*static_cast<int>(aString.length())),
4410 static_cast<intCrdT>(y+spc*cex),
4411 boxColor);
4412 drawString(aString, aFont, x, y, stringColor, cex, spc);
4413 }
4414
4415////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4416 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4417 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4418 int
4420 char strBuf[256];
4421
4422 std::ifstream iStream(fileName, std::ios_base::binary);
4423
4424 if (!(iStream.good()))
4425 return 1;
4426
4427 iStream.getline(strBuf, 10, '\n');
4428 if (!(iStream.good()))
4429 return 11;
4430 if (iStream.gcount() != 7)
4431 return 24;
4432 if(std::string(strBuf) != std::string("MJRRAW"))
4433 return 24;
4434
4435 int fileWide = -1;
4436 int fileTall = -1;
4437 int fileChans = -1;
4438 int fileBitPerChan = -1;
4439 bool fileIsSGN = true, fileHasS = false;
4440 bool fileIsInt = true, fileHasT = false;
4441 bool fileIsLTL = true, fileHasI = false;
4442
4443 iStream.getline(strBuf, 100, '\n');
4444 if (!(iStream.good()))
4445 return 11;
4446 if (iStream.gcount() != 93)
4447 return 26;
4448
4449 std::string::size_type tagIdx;
4450 std::string::size_type prcIdx = 0;
4451 std::string strBufS(strBuf);
4452 std::string delChrs("abcdefghijklmnopqrstuvwxyz");
4453 int stoiErrorCount = 0;
4454
4455 while(true) {
4456 tagIdx = strBufS.find_first_of(delChrs, prcIdx);
4457 if (tagIdx == std::string::npos)
4458 break;
4459 // std::cout << "suc: " << strBufS.substr(prcIdx) << std::endl;
4460 // std::cout << "tok: " << strBufS.substr(prcIdx, tagIdx-prcIdx) << std::endl;
4461 try {
4462 switch(strBufS[tagIdx]) {
4463 case 'x' : fileWide = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4464 case 'y' : fileTall = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4465 case 'c' : fileChans = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4466 case 'b' : fileBitPerChan = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4467 case 's' : fileIsSGN = (strBufS[prcIdx] == 'S'); fileHasS = true; break;
4468 case 't' : fileIsInt = (strBufS[prcIdx] == 'I'); fileHasT = true; break;
4469 case 'i' : fileIsLTL = (strBufS[prcIdx] == 'L'); fileHasI = true; break;
4470 }
4471 } catch (...) {
4472 stoiErrorCount++;
4473 }
4474 prcIdx=tagIdx+1;
4475 }
4476
4477 int fileBytePerChan = fileBitPerChan / 8;
4478
4479 // std::cout << "fileWide " << fileWide << std::endl;
4480 // std::cout << "fileTall " << fileTall << std::endl;
4481 // std::cout << "fileChans " << fileChans << std::endl;
4482 // std::cout << "fileBitPerChan " << fileBitPerChan << std::endl;
4483 // std::cout << "fileIsSGN " << fileIsSGN << std::endl;
4484 // std::cout << "fileIsInt " << fileIsInt << std::endl;
4485 // std::cout << "fileIsLTL " << fileIsLTL << std::endl;
4486 // std::cout << "fileBytePerChan: " << fileBytePerChan << std::endl;
4487
4488 if (stoiErrorCount > 0)
4489 return 29;
4490
4491 if (fileWide < 0)
4492 return 33;
4493 if (fileTall < 0)
4494 return 34;
4495 if (fileChans < 0)
4496 return 35;
4497 if (fileBitPerChan < 0)
4498 return 36;
4499
4500 if (fileWide == 0)
4501 return 8;
4502 if (fileTall == 0)
4503 return 9;
4504
4505 if (fileWide > intCrdMax)
4506 return 27;
4507 if (fileTall > intCrdMax)
4508 return 28;
4509
4510 resizeCanvas(fileWide, fileTall);
4511
4512 if (fileWide != numPixX)
4513 return(12);
4514 if (fileTall != numPixY)
4515 return(14);
4516
4517 if (!(fileHasT))
4518 fileIsInt = true;
4519
4520 if (!(fileHasS))
4521 fileIsSGN = ( !(fileIsInt)); // If file is missing 's', then assume it's compatable with 't'
4522
4523 if ((colorT::chanIsInt && fileIsSGN))
4524 return 23;
4525
4526 if ((colorT::chanIsInt && !fileIsInt) ||
4527 (colorT::chanIsFloat && fileIsInt))
4528 return 21;
4529
4530 if(fileChans != colorT::channelCount)
4531 return 19;
4532
4533 if(fileBitPerChan != colorT::bitsPerChan)
4534 return 20;
4535
4536 if (!(fileHasI))
4537 fileIsLTL = (platformEndianness() == endianType::LITTLE); // missing 'i', then assume LITTLE.
4538
4539 bool reverseBits = (( fileIsLTL && (platformEndianness() == endianType::BIG)) ||
4540 (!(fileIsLTL) && (platformEndianness() == endianType::LITTLE)));
4541
4542 intCrdT x, y;
4543 bool yNat = !(isIntAxOrientationNaturalY());
4544 bool xNat = isIntAxOrientationNaturalX();
4545 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
4546 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
4547 for(int ci=0; ci<fileChans; ci++) {
4548 if constexpr (colorT::chanIsInt) {
4549 colorChanArithLogType shft = (reverseBits ? colorT::bitsPerChan-8 : 0);
4550 /* Note that colorChanArithLogType is always an unsigned integer type, and thus we avoid compiler errors when trying to use | on a float.
4551 When chanIsInt, colorChanArithLogType is the same as colorChanType when chanIsInt -- so a NOOP because this part of the if only gets
4552 run when chanIsInt. */
4553 colorChanArithLogType pv = 0;
4554 for(int bi=0; bi<fileBytePerChan; bi++) {
4555 colorChanArithLogType uch = (unsigned char)iStream.get();
4556 if (!(iStream.good()))
4557 return 25;
4558 if (iStream.gcount() != 1)
4559 return 25;
4560 pv = pv | static_cast<colorChanArithLogType>(uch << shft);
4561
4562 if (reverseBits)
4563 shft -= 8;
4564 else
4565 shft += 8;
4566 }
4567 getPxColorRefNC(x, y).setChan(ci, static_cast<colorChanType>(pv));
4568 } else {
4569 iStream.read(strBuf, fileBytePerChan);
4570 getPxColorRefNC(x, y).setChan(ci, *((colorChanType*)strBuf));
4571 }
4572 }
4573 }
4574 }
4575 iStream.close();
4576 return 0;
4577 }
4578
4579////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4580 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4581 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4582 int
4584#ifndef MRASTER_FOUND_TIFF
4585 std::cerr << "ERROR: libTIFF no supported: readTIFFfile can't read " << fileName << std::endl;
4586 return 32;
4587#else
4588 TIFF* tif;
4589 uint32_t wTIFF, hTIFF;
4590 uint16_t pmTIFF, pcTIFF, sppTIFF, bpsTIFF, fmtTIFF;
4591
4592 // Open our tiff image
4593 if( !(tif = TIFFOpen(fileName.c_str(), "r")))
4594 return 1;
4595
4596 if(TIFFIsTiled(tif))
4597 return 23;
4598
4599 // All these tags are required -- bail if any are missing.
4600 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wTIFF))
4601 return 2;
4602 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hTIFF))
4603 return 3;
4604 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &sppTIFF))
4605 return 4;
4606 if( 1 != TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &pcTIFF))
4607 return 5;
4608 if( 1 != TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &pmTIFF))
4609 return 6;
4610 if( 1 != TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpsTIFF))
4611 return 7;
4612
4613 // This one is not required. If it's missing, it's 1 (unsigned integer).
4614 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &fmtTIFF))
4615 fmtTIFF = 1;
4616
4617 if (pmTIFF == PHOTOMETRIC_PALETTE)
4618 return 24;
4619
4620 //uint64_t cmTIFF = (1ULL << bpsTIFF) - 1ULL;
4621
4622 // // Dump out image metadata
4623 // std::cerr << "TIFF: " << fileName << std::endl;
4624 // std::cerr << " T WIDTH: " << wTIFF << std::endl;
4625 // std::cerr << " T HEIGHT: " << hTIFF << std::endl;
4626 // std::cerr << " T SPP: " << sppTIFF << std::endl;
4627 // std::cerr << " T PLNC: " << pcTIFF << std::endl;
4628 // std::cerr << " T PHOM: " << pmTIFF << std::endl;
4629 // std::cerr << " T BPS: " << bpsTIFF << std::endl;
4630 // std::cerr << " T MAX: " << cmTIFF << std::endl;
4631 // std::cerr << " T FMT: " << fmtTIFF << std::endl;
4632
4633 // Check file image size and reallocate aRamCanvas
4634 if(wTIFF < 1)
4635 return 8;
4636
4637 if(hTIFF < 1)
4638 return 9;
4639
4640 resizeCanvas(wTIFF, hTIFF);
4641
4642 uint32_t wRC = getNumPixX();
4643
4644 if ((pcTIFF != PLANARCONFIG_CONTIG) && (pcTIFF != PLANARCONFIG_SEPARATE))
4645 return 22;
4646
4647 if(wTIFF != wRC)
4648 return 12;
4649
4650 uint32_t hRC = getNumPixY();
4651
4652 if(hTIFF != hRC)
4653 return 14;
4654
4655 uint16_t sppRC = colorT::channelCount;
4656
4657 // MJR TODO NOTE readTIFFfile: We could read what we can instead of exiting. Check code is in the loop already to do that..
4658 if(sppTIFF != sppRC)
4659 return 19;
4660
4661 uint16_t bpsRC = colorT::bitsPerPixel / sppRC;
4662
4663 if(bpsTIFF != bpsRC)
4664 return 20;
4665
4666 // We only suport SAMPLEFORMAT_UINT & SAMPLEFORMAT_IEEEFP
4667 if ((fmtTIFF != SAMPLEFORMAT_UINT) && (fmtTIFF != SAMPLEFORMAT_IEEEFP))
4668 return 18;
4669
4670 if (( colorType::chanIsInt && (SAMPLEFORMAT_UINT != 1)) ||
4671 (!(colorType::chanIsInt) && (SAMPLEFORMAT_IEEEFP != 3)))
4672 return 21;
4673
4674 bool yNat = !(isIntAxOrientationNaturalY());
4675 bool xNat = isIntAxOrientationNaturalX();
4676 tsize_t scanlinesize = TIFFScanlineSize(tif);
4677 tdata_t scanLineBuffer = _TIFFmalloc(scanlinesize);
4678
4679 if(scanLineBuffer == NULL)
4680 return 16;
4681
4682 if (pcTIFF == PLANARCONFIG_CONTIG) { // Chunky
4683 for(uint32_t row=0; row<hTIFF; row++) {
4684 if( !(TIFFReadScanline(tif, scanLineBuffer, row)))
4685 return 17;
4686 char* p = (char*)(scanLineBuffer);
4687 for(uint32_t col=0; col<wTIFF; col++) {
4688 int x = (xNat ? col : wTIFF-col-1);
4689 int y = (yNat ? row : hTIFF-row-1);
4690 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4691 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4692 p = p + (bpsTIFF/8);
4693 }
4694 }
4695 }
4696 } else if (pcTIFF == PLANARCONFIG_SEPARATE) { // planar
4697 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4698 for(uint32_t row=0; row<hTIFF; row++) {
4699 if( !(TIFFReadScanline(tif, scanLineBuffer, row, samp)))
4700 return 17;
4701 char* p = (char*)(scanLineBuffer);
4702 for(uint32_t col=0; col<wTIFF; col++) {
4703 int x = (xNat ? col : wTIFF-col-1);
4704 int y = (yNat ? row : hTIFF-row-1);
4705 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4706 p = p + (bpsTIFF/8);
4707 }
4708 }
4709 }
4710 }
4711
4712 _TIFFfree(scanLineBuffer);
4713 TIFFClose(tif);
4714 return 0;
4715#endif
4716 }
4717
4718////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4719 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4720 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4721 inline bool
4723#ifndef MRASTER_FOUND_TIFF
4724 return true;
4725#else
4726 return false;
4727#endif
4728 }
4729
4730////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4731 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4732 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4735 double Xo,
4736 double Yo,
4737 double oScale,
4738 colorArgType errorColor,
4739 interpolationType interpMethod) {
4741 for(intCrdT y=0; y<numPixY; y++) {
4742 for(intCrdT x=0; x<numPixX; x++) {
4743 double xT = (x-Xo);
4744 double yT = (y-Yo);
4745 mjr::point2d<double> fv = f(xT, yT);
4746 double xS = fv.x / oScale + Xo;
4747 double yS = fv.y / oScale + Yo;
4748 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4749 newRamCanvas.drawPointNC(x, y, errorColor);
4750 } else {
4751 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4752 }
4753 }
4754 }
4755 return newRamCanvas;
4756 }
4757
4758////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4759 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4760 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4763 double Xo,
4764 double Yo,
4765 double oScale,
4766 colorArgType errorColor,
4767 interpolationType interpMethod) {
4769 for(intCrdT y=0; y<numPixY; y++) {
4770 for(intCrdT x=0; x<numPixX; x++) {
4771 double xT = x-Xo;
4772 double yT = y-Yo;
4773 double xS = (HAMatrix[0] * xT + HAMatrix[1] * yT + HAMatrix[2]) / oScale + Xo;
4774 double yS = (HAMatrix[3] * xT + HAMatrix[4] * yT + HAMatrix[5]) / oScale + Yo;
4775 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4776 newRamCanvas.drawPointNC(x, y, errorColor);
4777 } else {
4778 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4779 }
4780 }
4781 }
4782 return newRamCanvas;
4783 }
4784
4785////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4786 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4787 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4790 double rScale,
4791 double Xo,
4792 double Yo,
4793 double oScale,
4794 colorArgType errorColor,
4795 interpolationType interpMethod) {
4797 for(intCrdT y=0; y<numPixY; y++) {
4798 for(intCrdT x=0; x<numPixX; x++) {
4799 double xT = (x - Xo);
4800 double yT = (y - Yo);
4801 double rT = std::hypot(xT, yT) / rScale;
4802 // double rS = mjr::math::uply::eval(RPoly, rT);
4803 double rS = RPoly[0];
4804 for (unsigned int i=1; i<RPoly.size(); i++)
4805 rS = rS*rT + RPoly[i];
4806 double xS = xT * rS / oScale + Xo;
4807 double yS = yT * rS / oScale + Yo;
4808 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4809 newRamCanvas.drawPointNC(x, y, errorColor);
4810 } else {
4811 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4812 }
4813 }
4814 }
4815 return newRamCanvas;
4816 }
4817
4818////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4819 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4820 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4823 std::vector<double> const& BiPolyY,
4824 double Xo,
4825 double Yo,
4826 double oScale,
4827 colorArgType errorColor,
4828 interpolationType interpMethod) {
4830 for(intCrdT y=0; y<numPixY; y++) {
4831 for(intCrdT x=0; x<numPixX; x++) {
4832 double xT = (x-Xo);
4833 double yT = (y-Yo);
4834 double xS = mjr::math::bply::eval(BiPolyX, xT, yT) / oScale + Xo;
4835 double yS = mjr::math::bply::eval(BiPolyY, xT, yT) / oScale + Yo;
4836 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4837 newRamCanvas.drawPointNC(x, y, errorColor);
4838 } else {
4839 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4840 }
4841 }
4842 }
4843 return newRamCanvas;
4844 }
4845
4846} // end namespace mjr
4847
4848#define MJR_INCLUDE_ramCanvasTpl
4849#endif
User include file for color types.
Internal include file for ramCanvas types.
std::function< void(colorTpl &)> cr2voidType
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
Class providing off-screen drawing functionality.
pointFltType int2realCorner(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...
void freeCanvas()
Free the pixel memory (i)
void drawRectangle(pointFltType *thePoints)
interpolationType
Enum for drawing Mode.
@ TRUNCATE
Coordinates are truncated (fractional bits chopped off)
@ AVERAGE9
Average of 9 sourounding pixels.
@ AVERAGE4
Average of four sourounding pixels.
@ NEAREST
Coordinates are rounded.
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 applyHomoPixTfrm(colorT &(colorT::*HPT)())
Apply a homogeneous pixel transformation.
void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3)
void applyHomoPixTfrm(colorT &(colorT::*HPT)(int, int, int, int), int, int, int, int)
void drawLine(pointFltType point1)
void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color)
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 triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT *pts, bool findMin)
Used to find the left and right edges of a triangle.
pointFltType int2realCorner(intCrdT x, intCrdT y, int sideX, int sideY)
Given integer x & y coordinates, produce real x & y coordinates for one of the pixel's corners.
void drawFillCircle(pointIntType centerPoint, intCrdT radiusX)
void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y, colorArgType color)
Draw Piece-Wise Linear Curves.
void drawFillTriangleUtl(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorT c1, colorT c2, colorT c3, bool solid)
Utliity function behind the drawFillTriangle() functions.
void drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc)
Render a string using Hershey ASCII Fonts.
void drawFillRectangle(pointIntType *thePoints)
pointFltType int2real(intCrdT x, intCrdT y)
Convert real x & y coordinates to integer x & y coordinates.
int writeRAWfile(std::string fileName)
Simplified overload for writeRAWfile() that only requires the filename.
void drawLine(pointFltType point1, pointFltType point2, colorArgType color)
intCrdT statNumNonZeroPixels()
void moveTo(pointIntType thePoint)
void flipTranspose()
Loss-less, vertical flip of the canvas about the center.
void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor)
int writeTIFFfile(std::string fileName, bool markAlpha=true)
Simplified overload for writeTIFFfile() that only requires the filename.
void adjoinCanvasRight(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color)
Draw an unfilled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
endianType
Endianness Identifiers.
@ AUTO
Whatever the platform uses.
void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color)
void updRealCoords()
Several internal parameters are maintained within this class that make conversion between real coordi...
void computeConvolutionMatrixGausian(double *kernel, int kSize, double sd)
Compute a Gaussian convolution kernel (use with divisor==1.0).
std::function< color8c8b(rcSimpleIntCrdT, rcSimpleIntCrdT)> intCrd2ColType
void rotate180()
Loss-less 180 degree rotation of the canvas about the center.
realAxisOrientation
Enum for real axis orientation.
@ INVERTED
Real axis is inverted with respect to the integer axis.
@ NATURAL
Real axis is not inverted with respect to the integer axis.
~ramCanvasTpl()
Destructor deallocates memory for the canvas.
void flipVert()
Loss-less, vertical flip of the canvas about the center.
void drawFillTriangle(pointFltType *thePoints)
void drawPoint(fltCrdT x, fltCrdT y, colorArgType color)
void drawFillTriangle(pointIntType *thePoints)
void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y, colorArgType color)
void clrCanvasChannelToMin(int chan)
Set the given channel to the minimum value.
colorChanType getPxColorChanWrap(fltCrdT x, fltCrdT y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::function< color8c8b(rcSimpleFltCrdT, rcSimpleFltCrdT)> fltCrd2ColType
colorChanType getPxColorChanWrap(intCrdT x, intCrdT y) const
Returns a copy of the color channel value at the given coordinates wrapping x & y if out of range.
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)
colorT * clonePixels()
Return a clone (a copy) of the raw pixel store.
void applyHomoPixTfrm(colorT &(colorT::*HPT)(int, int), int, int)
colorChanType getPxColorChanWrap(pointIntType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void resizeCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p)
Resize the canvas to the given size.
intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color)
void drawLine(pointFltType point1, pointFltType point2)
void drawPoint(intCrdT x, intCrdT y)
void writeUIntToStream(std::ostream &oStream, endianType endianness, int numBytes, uint64_t data)
Write an unsigned integer to a stream with given length and endianness.
void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3)
void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
drawModeType
Enum for drawing Mode.
@ DIFFCLAMP
See: tfrmDiffClamp()
@ SET
Simply set the pixel value to the new value.
@ MULTCLAMP
See: tfrmMultClamp()
void setDefaultDrawMode()
Set the default draw mode.
void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3)
void scaleDown1pt(int xfactor)
Scale down using only the upper left pixel from each block.
void applyHomoPixTfrm(colorT &(colorT::*HPT)(colorT, colorT, colorT), colorT, colorT, colorT)
void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color)
void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc)
void applyHomoPixTfrm(colorT &(colorT::*HPT)(double, double, double, double, double), double, double, double, double, double)
void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3)
void drawLine(pointIntType point1)
void drawTriangle(pointIntType *thePoints, colorArgType color)
void clrCanvasChannelToMax(int chan)
Set the given channel to the maximum value.
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)
void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color)
Draw a line.
void cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
This function will crop the canvas to the given rectangular region.
fltCrdT getCanvasWidD()
Width of the display (real coord)
void drawPLCurve(int numPoints, pointFltType *thePoints, colorArgType color)
void drawStringBox(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc)
Renders a filled, bounding box for the given string as rendered via drawString.
void applyHomoPixTfrm(colorT &(colorT::*HPT)(colorT, colorT, colorT, colorT), colorT, colorT, colorT, colorT)
void setDfltColor(std::string cornerColor)
void clrCanvas(colorArgType color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setDrawMode(drawModeType newDrawMode)
Set the current drawing mode NOOP if enableDrawModes is false.
void setDfltColor(const char *cornerColor)
void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3, colorArgType color)
void drawRectangle(pointIntType *thePoints, colorArgType color)
void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color)
intAxisOrientation getIntAxOrientationX()
Get the integer X axis orientation.
void incPxChan(fltCrdT x, fltCrdT y, colorChanType v=1)
void newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p)
Change the real coordinate system associated with a canvas.
void combineRamCanvasBinOp(colorT &(colorT::*HPT)(colorT), const ramCanvasTpl &theCanvas, intCrdT trgX=0, intCrdT trgY=0, intCrdT wide=-1, intCrdT tall=-1, intCrdT srcX=0, intCrdT srcY=0)
This function takes a ramCanvasTpl and combines it with the current ramCanvasTpl using the provided b...
colorChanType getPxColorChanWrap(pointFltType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void applyHomoPixTfrm(colorT &(colorT::*HPT)(colorT), colorT)
void drawPointS(intCrdT x, intCrdT y, colorArgType color)
Draw a point without any special drawing options.
void drawPoint(pointIntType thePoint)
void tformPixel(pointFltType thePoint, colorType::cr2voidType tform)
void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color)
Draw an un-filled triangle.
void drawLine(pointIntType point1, pointIntType point2)
void setRealAxOrientationX(realAxisOrientation orientation)
Set the real X axis orientation.
void moveTo(pointFltType thePoint)
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.
void rotate90CW()
Loss-less 90 degree clockwise rotation of the canvas about the center.
colorT getPxColorInterpNear(double x, double y)
Returns the nearest neighbor interpolated color value at the the given coordinates.
void clrCanvasToWhite()
Clear the canvas to black.
void setDfltColor(colorArgType color)
Set the default color.
void flipHorz()
Loss-less, horizontal flip of the canvas about the center.
void moveTo(intCrdT x, intCrdT y)
Set the current default point to the given coordinates.
void drawCircle(pointFltType centerPoint, fltCrdT radiusX)
void applyHomoPixTfrm(colorT &(colorT::*HPT)(double, double), double, double)
void drawTriangle(pointFltType *thePoints, colorArgType color)
fltCrdT getMaxRealX()
x coord of max (real coord)
void applyHomoPixTfrm(colorT &(colorT::*HPT)(colorT, colorT), colorT, colorT)
void drawPLCurve(int numPoints, pointIntType *thePoints, colorArgType color)
void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color)
void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color)
colorT getPxColorChan(pointFltType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void applyHomoPixTfrm(colorT &(colorT::*HPT)(double, double, double, double, double, double), double, double, double, double, double, double)
bool isIntAxOrientationNaturalY()
Get the integer Y axis orientation.
void applyPixelRefFun(colorT::cr2voidType f)
Apply a a function to a each pixel via refrence.
colorT getPxColorWrap(pointFltType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawFillCircle(fltCrdT radiusX)
void reallocCanvas(intCrdT numPixX_p, intCrdT numPixY_p)
Destroy the current pixel memory and reallocate a new pixel space of the given size.
int isCliped(intCrdT x, intCrdT y) const
bool supportLibTIFF()
Is libTIFF supported – that is: will the readTIFFfile() method do anything?
void drawPointNC(rcSimpleIntCrdT x, rcSimpleIntCrdT y, colorArgType color)
ramCanvasTpl(const ramCanvasTpl &theCanvas)
Copy constructor.
void scaleUpProximal(int xfactor)
Scale up the image using proximal interpolation.
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
This is an overloaded member function, provided for convenience. It differs from the above function o...
void scaleDownMean(int xfactor)
Scale down using the mean pixel value from each block.
int exportRasterData(void *&rasterData, intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, int redChan, int greenChan, int blueChan, int alphaChan)
Extract raster data from the image, and pack it into a typical form used by imaging applications.
void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3)
void clrCanvasToBlack()
Clear the canvas to black.
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)
void drawRectangle(pointFltType point1, pointFltType point2)
void drawTriangle(pointFltType *thePoints)
void colorizeFltCanvas(std::function< colorT(fltCrdT, fltCrdT)> cFun)
colorT getPxColorInterpTrunc(double x, double y)
Returns the truncated interpolated color value at the the given coordinates.
void drawCircle(pointIntType centerPoint, intCrdT radiusX)
colorT getPxColorInterpBLin(double x, double y)
Returns the bilinear interpolated color value at the the given coordinates.
void setDfltColor(colorChanType r, colorChanType g, colorChanType b)
ramCanvasTpl geomTfrmRevBiPoly(std::vector< double > const &BiPolyX, std::vector< double > const &BiPolyY, double Xo, double Yo, double oScale, colorArgType errorColor=colorCornerEnum::GREEN, interpolationType interpMethod=interpolationType::BILINEAR)
Geometric Transform via bivariate polynomial implemented with Reverse Mapping.
void colorizeIntCanvas(std::function< colorT(intCrdT, intCrdT)> cFun)
void drawLine(pointIntType point1, pointIntType point2, colorArgType color)
int readTIFFfile(std::string fileName)
If the libTIFF library was found at build time, this function will read a TIFF file into current ramC...
void rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY)
Points the pixels pointer at a new pixel store, and updates coordinates.
void drawPoint(pointFltType thePoint)
ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p=-1, fltCrdT maxRealX_p=1, fltCrdT minRealY_p=-1, fltCrdT maxRealY_p=1)
Most commonly used constructor.
void incPxChan(pointFltType thePoint, colorChanType v=1)
void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color)
Draw an un-filled circle.
fltCrdT int2realSideY(intCrdT y, int side)
Given integer y coordinate, produce real y coordinate for one of the pixel's edge.
ramCanvasTpl geomTfrmRevAff(std::vector< double > const &HAMatrix, double Xo, double Yo, double oScale, colorArgType errorColor=colorCornerEnum::GREEN, interpolationType interpMethod=interpolationType::BILINEAR)
Homogenious Affine Geometric Transform implemented with Reverse Mapping.
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)
void applyHomoPixTfrm(colorT &(colorT::*HPT)(int, int, int), int, int, int)
void combineRamCanvasMean(ramCanvasTpl *theCanvasList, const int N)
Take a list of ramCanvasTpl objects and combine them with the current ramCanvasTpl using mean.
void moveTo(fltCrdT x, fltCrdT y)
void setIntAxOrientationX(intAxisOrientation orientation)
Set the integer X axis orientation.
void drawPLCurve(int numPoints, pointIntType *thePoints)
intCrdT realDelta2intY(fltCrdT y) const
Convert real distance on the y coordinate axis to an integral distance.
void autoMaxHistStrechRGB()
Computes a, possibly different, linear grey level scale homogeneous pixel transformation on each chan...
void convolution(double *kernel, int kSize)
colorT getPxColorWrap(intCrdT x, intCrdT y) const
Returns a copy of the color at the given coordinates wrapping x & y if out of range.
void newIntCoordsNC(intCrdT numPixX_p, intCrdT numPixY_p)
Change the logical coordinate sizes.
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)
void insertCanvas(const ramCanvasTpl &theCanvas, rcSimpleIntCrdT x1=0, rcSimpleIntCrdT y1=0)
void drawCircle(fltCrdT radiusX)
colorT getPxColorInterpAvg9(double x, double y)
Returns the average 9 interpolated color value at the the given coordinates.
color8c8b getPxColorNC(rcSimpleIntCrdT x, rcSimpleIntCrdT y) const
void drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor)
Render a glyph from the Hershey character set.
int writeRAWfile(std::string fileName, rcConT pxFilter)
Write a MJRRAW file.
void tformPixel(fltCrdT x, fltCrdT y, colorType::cr2voidType tform)
ramCanvasTpl geomTfrmRevArb(mjr::point2d< double >(*f)(double, double), double Xo, double Yo, double oScale, colorArgType errorColor=colorCornerEnum::GREEN, interpolationType interpMethod=interpolationType::BILINEAR)
Geometric Transform via provided mapping function implemented with Reverse Mapping.
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
This is an overloaded member function, provided for convenience. It differs from the above function o...
void applyHomoPixTfrm(colorT &(colorT::*HPT)(double, double, double, double), double, double, double, double)
colorT getPxColor(pointFltType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
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.
colorT getPxColorWrap(pointIntType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
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 applyHomoPixTfrm(colorT &(colorT::*HPT)(double), double)
void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color)
void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color)
Draw a filled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
void tformPixel(intCrdT x, intCrdT y, colorType::cr2voidType tform)
Transform the pixel at the specified coordinates.
void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX)
int isOnCanvas(intCrdT x, intCrdT y) const
void drawPoint(colorArgType color)
void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color)
colorT getPxColorInterpAvg4(double x, double y)
Returns the average 4 interpolated color value at the the given coordinates.
void colorizeIntCanvas(std::function< colorT(pointIntType)> cFun)
ramCanvasTpl(ramCanvasTpl &&theCanvas)
Move constructor.
void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y)
int writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha=true)
Write a TIFF format image file.
void drawPLCurve(int numPoints, pointFltType *thePoints)
fltCrdT getPixWidY()
Height of a pixel (real coord)
void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color)
Draw an un-filled circle.
void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color)
realAxisOrientation getRealAxOrientationY()
Get the real Y axis orientation.
void clrCanvas()
Clear the canvas.
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)
int writeTGAfile(std::string fileName)
Write a 24-bit (8-bit per channel) RGB, TGA format graphics file.
void drawTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color)
endianType platformEndianness()
Determine the platform's endianness.
int readRAWfile(std::string fileName)
Read RAW file.
colorT getPxColorChan(intCrdT x, intCrdT y) const
Returns a copy of the color channel value at the given coordinates.
fltCrdT getMinRealX()
x coord of min (real coord)
void rotate90CCW()
Loss-less 90 degree counter clockwise rotation of the canvas about the center.
void drawRectangle(pointIntType point1, pointIntType point2)
void scaleDownMax(int xfactor)
Scale down using only the pixel with maximum luminosity in each block.
fltCrdT int2realX(intCrdT x)
Convert integral x coordinate to real x coordinate.
void drawTriangle(pointIntType *thePoints)
fltCrdT int2realY(intCrdT y)
Convert integral y coordinate to real y coordinate.
void drawPoint(rcSimpleIntCrdT x, rcSimpleIntCrdT y, colorArgType color)
void setIntAxOrientationY(intAxisOrientation orientation)
Set the integer Y axis orientation.
void colorizeFltCanvas(std::function< colorT(pointFltType)> cFun)
ramCanvasTpl geomTfrmRevRPoly(std::vector< double > const &RPoly, double rScale, double Xo, double Yo, double oScale, colorArgType errorColor=colorCornerEnum::GREEN, interpolationType interpMethod=interpolationType::BILINEAR)
Geometric Transform via Radial Polynomial implemented with Reverse Mapping.
void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color1, colorArgType color2, colorArgType color3)
Draw a filled triangle using barycentric color interpolation.
void expandCanvas(rcSimpleIntCrdT new_numPixX_p, rcSimpleIntCrdT new_numPixY_p, rcSimpleIntCrdT x1=0, rcSimpleIntCrdT y1=0, colorArgType color=color8c8b(color8c8b::minChanVal))
colorT getPxColorChan(pointIntType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2)
void autoHistStrech()
Computes a linear grey level scale homogeneous pixel transformation.
drawModeType getDrawMode()
Get the current drawing mode.
colorT getPxColorWrap(fltCrdT x, fltCrdT y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void applyHomoPixTfrm(colorT &(colorT::*HPT)(double, double, double), double, double, double)
colorT getPxColorChan(fltCrdT x, fltCrdT y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawFillCircle(intCrdT radiusX)
ramCanvasTpl & operator=(ramCanvasTpl &&theCanvas)
Move assignment operator.
void adjoinCanvasBottom(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
colorT getPxColorInterpolate(double x, double y, interpolationType interpMethod=interpolationType::BILINEAR)
Returns the interpolated color value at the the given coordinates using the given interpolation metho...
void computeConvolutionMatrixBox(double *kernel, int kSize)
Compute a box blur convolution kernel (use with divisor==1.0).
void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color)
void applyHomoPixTfrm(colorT &(colorT::*HPT)(int), int)
void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y)
void drawPoint(pointIntType thePoint, colorArgType color)
void incPxChan(intCrdT x, intCrdT y, colorChanType v=1)
Increment the specified color channel of the pixel at the given coordinates by the specified value.
void convolution(double *kernel, int kSize, double divisor)
void drawFillRectangle(pointIntType point1, pointIntType point2)
intAxisOrientation
Enum for integer axis orientation.
colorT * getPixels()
Returns a pointer to the raw pixel store.
void tformPixel(pointIntType thePoint, colorType::cr2voidType tform)
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().
fltCrdT int2realSideX(intCrdT x, int side)
Given integer x coordinate, produce real x coordinate for one of the pixel's edge.
void convolution(double *kernel, int kWide, int kTall, double divisor)
Apply a convolution filter.
void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3, colorArgType 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 drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color)
Draw a triangle filled with a solid color using a nicely optimized, horizontal scan conversion algori...
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 incPxChan(pointIntType thePoint, colorChanType v=1)
ramCanvasTpl()
No arg constructor.
void drawLine(pointIntType point1, colorArgType color)