Loading [MathJax]/extensions/tex2jax.js
MRaster lib 22.0.0.0
Image Processing Library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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)> fltCrd2Col; //!< std::function type floating point coordinates to a color
166 typedef std::function<colorT (pointFltType)> fltPnt2Col; //!< std::function type floating point point to a color
167 typedef std::function<colorT (intCrdT, intCrdT)> intCrd2Col; //!< std::function type int point coordinates to a color
168 typedef std::function<colorT (pointIntType)> intPnt2Col; //!< 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. */
345 endianType platformEndianness();
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(). */
355 void updRealCoords();
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) */
379 void freeCanvas();
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. */
431 ramCanvasTpl();
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 */
447 ramCanvasTpl(ramCanvasTpl&& theCanvas);
448 //--------------------------------------------------------------------------------------------------------------------------------------------------------
449 /** Move assignment operator */
450 ramCanvasTpl& operator=(ramCanvasTpl&& theCanvas);
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. */
617 void rotate90CW();
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. */
622 void rotate90CCW();
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. */
640 void flipTranspose();
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. */
749 ramCanvasTpl geomTfrmRevArb(mjr::point2d<double> (*f)(double, double),
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::cr2void_func_t 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". */
839 void autoHistStrech();
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.*/
844 void autoMaxHistStrechRGB();
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(). */
882 void clrCanvasToBlack();
883 //--------------------------------------------------------------------------------------------------------------------------------------------------------
884 /** Clear the canvas to black. Faster than clrCanvas(). */
885 void clrCanvasToWhite();
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 */
897 void clrCanvas(colorArgType color);
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 }
937 inline void drawPoint() { drawPoint(dfltX, dfltY, dfltColor); }
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 Line Drawing Methods */
950 //@{
951 //--------------------------------------------------------------------------------------------------------------------------------------------------------
952 /** Draw a line.
953 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
954 current canvas.
955 @param x1 x coordinate of the first point
956 @param y1 y coordinate of the first point
957 @param x2 x coordinate of the second point
958 @param y2 y coordinate of the second point
959 @param color The color to use
960
961 @par Performance Note
962 This function will perform better if (x1,y2) and (x2,y2) are in the clip region. Further x1<x2 will save several steps in
963 the algorithm.
964
965 @par Algorithm Notes
966 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
967 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
968 for positive slope lines and for negative slope lines.
969
970 The algorithms used to draw lines in the last four cases are related to the classic algorithm presented by Bresenham in 1965 and the
971 extensions to Bresenham's algorithm given by Pitteway in 1967 and Van Aken in 1984. The basic algorithm described by Bresenham, Pitteway, and Van
972 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
973 obvious extensions to the midpoint algorithm. Each case is customized and optimized for the given slope class.
974
975 The clipping algorithm used for the last slope classes is similar in spirit to the Cohen-Sutherland Line-Clipping algorithm, but is optimized
976 for each slope class. Several pre-checks are made in order to avoid the slope computations in the Cohen-Sutherland algorithm -- in fact intersections
977 are only computed if absolutely required. Note that the only floating point computations in this function are the intersection computations, and they
978 will be avoided completely if the given line need not be clipped.*/
979 void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
980 inline void drawLine(pointFltType point1) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), dfltColor); }
981 inline void drawLine(pointFltType point1, colorArgType color) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), color); }
982 inline void drawLine(pointIntType point1) { drawLine( dfltX, dfltY, point1.x, point1.y, dfltColor); }
983 inline void drawLine(pointIntType point1, colorArgType color) { drawLine( dfltX, dfltY, point1.x, point1.y, color); }
984 inline void drawLine(pointFltType point1, pointFltType point2) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
985 inline void drawLine(pointFltType point1, pointFltType point2, colorArgType color) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
986 inline void drawLine(pointIntType point1, pointIntType point2) { drawLine( point1.x, point1.y, point2.x, point2.y, dfltColor); }
987 inline void drawLine(pointIntType point1, pointIntType point2, colorArgType color) { drawLine( point1.x, point1.y, point2.x, point2.y, color); }
988 inline void drawLine(intCrdT x, intCrdT y) { drawLine( dfltX, dfltY, x, y, dfltColor); }
989 inline void drawLine(fltCrdT x, fltCrdT y) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), dfltColor); }
990 inline void drawLine(intCrdT x, intCrdT y, colorArgType color) { drawLine( dfltX, dfltY, x, y, color); }
991 inline void drawLine(fltCrdT x, fltCrdT y, colorArgType color) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), color); }
992 inline void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
993 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
994 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawLine( real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
995 //@}
996
997 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
998 /** @name Unfilled Triangle Drawing Methods */
999 //@{
1000 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1001 /** Draw an un-filled triangle
1002 @bug Some pixels may be drawn more than once.
1003 @param x1 The x coordinate of the first point
1004 @param y1 The y coordinate of the first point
1005 @param x2 The x coordinate of the second point
1006 @param y2 The y coordinate of the second point
1007 @param x3 The x coordinate of the third point
1008 @param y3 The y coordinate of the third point
1009 @param color The color to use for the triangle */
1010 void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1011 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); }
1012 inline void drawTriangle(pointFltType *thePoints) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1013 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1014 real2intX(thePoints[2].x), real2intY(thePoints[2].y), dfltColor); }
1015 inline void drawTriangle(pointFltType *thePoints, colorArgType color) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1016 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1017 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1018 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); }
1019 inline void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1020 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1021 real2intX(point2.x), real2intY(point2.y),
1022 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1023 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1024 real2intX(point2.x), real2intY(point2.y),
1025 real2intX(point3.x), real2intY(point3.y), color); }
1026 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); }
1027 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); }
1028 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); }
1029 inline void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1030 //@}
1031
1032 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1033 /** @name Filled Triangle Drawing Methods */
1034 //@{
1035 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1036 /** Draw a triangle filled with a solid color using a nicely optimized, horizontal scan conversion algorithm.
1037 @bug Triangles not entirely on the canvas are not rendered.
1038 @bug Not thread safe.
1039 @param x1 The x coordinate of the first point
1040 @param y1 The y coordinate of the first point
1041 @param x2 The x coordinate of the second point
1042 @param y2 The y coordinate of the second point
1043 @param x3 The x coordinate of the third point
1044 @param y3 The y coordinate of the third point
1045 @param color The color to use for the triangle */
1046 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1047 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); }
1048 inline void drawFillTriangle(pointFltType *thePoints) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1049 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1050 real2intX(thePoints[2].x), real2intY(thePoints[2].y), dfltColor); }
1051 inline void drawFillTriangle(pointFltType *thePoints, colorArgType color) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1052 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1053 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1054 inline void drawFillTriangle(pointIntType *thePoints) { drawFillTriangle(thePoints[0].x, thePoints[0].y,
1055 thePoints[1].x, thePoints[1].y,
1056 thePoints[2].x, thePoints[2].y, dfltColor); }
1057 inline void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawFillTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1058 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1059 real2intX(point2.x), real2intY(point2.y),
1060 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1061 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1062 real2intX(point2.x), real2intY(point2.y),
1063 real2intX(point3.x), real2intY(point3.y), color); }
1064 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); }
1065 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); }
1066 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); }
1067 inline void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawFillTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1068 //@}
1069
1070 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1071 /** @name Shaded Triangle Drawing Methods */
1072 //@{
1073 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1074 /** Draw a filled triangle using barycentric color interpolation.
1075 @bug Triangles not entirely on the canvas are not rendered.
1076 @bug Degenerate trainagles are not rendered
1077 @bug Painfully slow
1078 @param x1 The x coordinate of the first point
1079 @param y1 The y coordinate of the first point
1080 @param x2 The x coordinate of the second point
1081 @param y2 The y coordinate of the second point
1082 @param x3 The x coordinate of the third point
1083 @param y3 The y coordinate of the third point
1084 @param color1 The color of the first point (x1, y1)
1085 @param color2 The color of the second point (x2, y2)
1086 @param color3 The color of the third point (x3, y3) */
1087 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color1, colorArgType color2, colorArgType color3);
1088 //@}
1089
1090 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1091 /** @name Unfilled Rectangle Drawing Functions */
1092 //@{
1093 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1094 /** Draw an unfilled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1095 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
1096 the bounds of the canvas using the specified color.
1097 @param x1 The x coordinate of first corner
1098 @param y1 The y coordinate of first corner
1099 @param x2 The x coordinate of second corner
1100 @param y2 The y coordinate of second corner
1101 @param color The color to use */
1102 void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1103 inline void drawRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1104 inline void drawRectangle(pointIntType point1, pointIntType point2) { drawRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1105 inline void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1106 inline void drawRectangle(pointFltType point1, pointFltType point2) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1107 inline void drawRectangle(pointIntType *thePoints, colorArgType color) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1108 inline void drawRectangle(pointFltType *thePoints) { drawRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1109 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); }
1110 inline void drawRectangle(pointIntType *thePoints) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1111 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1112 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1113 inline void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawRectangle(x1, y1, x2, y2, dfltColor); }
1114 //@}
1115
1116 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1117 /** @name Filled Rectangle Drawing Methods */
1118 //@{
1119 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1120 /** Draw a filled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1121 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
1122 the bounds of the canvas using the specified color.
1123 @param x1 The x coordinate of first corner
1124 @param y1 The y coordinate of first corner
1125 @param x2 The x coordinate of second corner
1126 @param y2 The y coordinate of second corner
1127 @param color The color to use */
1128 void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1129 inline void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1130 inline void drawFillRectangle(pointIntType point1, pointIntType point2) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1131 inline void drawFillRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1132 inline void drawFillRectangle(pointFltType point1, pointFltType point2) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1133 inline void drawFillRectangle(pointIntType *thePoints, colorArgType color) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1134 inline void drawFillRectangle(pointFltType *thePoints) { drawFillRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1135 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); }
1136 inline void drawFillRectangle(pointIntType *thePoints) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1137 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1138 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1139 inline void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawFillRectangle(x1, y1, x2, y2, dfltColor); }
1140 //@}
1141
1142 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1143 /** @name Unfilled Circle Drawing Methods */
1144 //@{
1145 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1146 /** Draw an un-filled circle.
1147 The algorithm used is based upon the one presented in "A Linear Algorithm for Incremental Digital Display of Circular Arcs" published in the
1148 Communications of the AMC in Feb 1977 and written by J.E. Bresenham. Bresenham's algorithm has been significantly improved by using only integer
1149 arithmetic and adding second order differences to the computation -- much the way the line drawing algorithm works in this package. The algorithm
1150 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
1151 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.
1152 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
1153 optimized.
1154 @bug Draws everyting even if it's off the canvas.
1155 @param centerX The x coordinate of the center
1156 @param centerY The y coordinate of the center
1157 @param radiusX The radius of the circle
1158 @param color The color to draw the circle with */
1159 void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1160 inline void drawCircle(intCrdT radiusX) { drawCircle(dfltX, dfltY, radiusX, dfltColor); }
1161 inline void drawCircle(fltCrdT radiusX) { drawCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1162 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1163 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1164 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX) { drawCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1165 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1166 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1167 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1168 inline void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawCircle(centerX, centerY, radiusX, dfltColor); }
1169 //@}
1170
1171 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1172 /** @name Filled Circle Drawing Methods */
1173 //@{
1174 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1175 /** Draw an un-filled circle.
1176 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
1177 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
1178 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
1179 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
1180 X axis -- i.e. the radius of the drawn circle will be measured horizontally. This function is well optimized.
1181 @bug Draws everyting even if it's off the canvas.
1182 @param centerX The x coordinate of the center
1183 @param centerY The y coordinate of the center
1184 @param radiusX The radius of the circle
1185 @param color The color to draw the circle with */
1186 void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1187 inline void drawFillCircle(fltCrdT radiusX) { drawFillCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1188 inline void drawFillCircle(intCrdT radiusX) { drawFillCircle(dfltX, dfltY, radiusX, dfltColor); }
1189 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1190 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1191 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1192 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1193 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1194 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1195 inline void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawFillCircle(centerX, centerY, radiusX, dfltColor); }
1196 //@}
1197
1198 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1199 /** @name Piece-Wise Linear Curve Drawing Methods */
1200 //@{
1201 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1202 /** Draw Piece-Wise Linear Curves
1203 @bug Some pixels may be drawn more than once.
1204 */
1205 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y, colorArgType color);
1206 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y);
1207 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y, colorArgType color);
1208 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y);
1209 void drawPLCurve(int numPoints, pointIntType *thePoints, colorArgType color);
1210 void drawPLCurve(int numPoints, pointIntType *thePoints);
1211 void drawPLCurve(int numPoints, pointFltType *thePoints, colorArgType color);
1212 void drawPLCurve(int numPoints, pointFltType *thePoints);
1213 //@}
1214
1215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1216 /** @name Hershey Glyph Rendering Utility Functions */
1217 //@{
1218 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1219 /** Render a glyph from the Hershey character set.
1220 The glyph is rendered with its origin at the given coordinates. This function is intended to provide only the most basic glyph rendering. For
1221 example, glyphs are rendered with the line drawing functions, and therefore are not anti-aliased.
1222 @param glyphNum The character number of the glyph to render
1223 @param x The x coordinate at which to render the glyph
1224 @param y The x coordinate at which to render the glyph
1225 @param magX The magnification of the glyph in the x direction
1226 @param magY The magnification of the glyph in the y direction
1227 @param aColor The color with which to render the glyph */
1228 void drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor);
1229 void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor) { drawHersheyGlyph(glyphNum, real2intX(x), real2intY(y), magX, magY, aColor); }
1230 //@}
1231
1232 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1233 /** @name ASCII Character Rendering.
1234 What are font rendering functions doing in a raster graphics library? Sometimes I like to put a label on image.*/
1235 //@{
1236 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1237 /** Render a string using Hershey ASCII Fonts.
1238 While the string is rendered with fixed font spacing, the Hershey fonts are not fixed width fonts.
1239 @param aString The string
1240 @param aFont The font to set the default with
1241 @param x The x coordinate at which to render the first glyph
1242 @param y The x coordinate at which to render the first glyph
1243 @param aColor The color with which to render the glyphs
1244 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1245 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1246 void drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc);
1247 void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc) {
1248 drawString(aString, aFont, real2intX(x), real2intY(y), aColor, cex, spc);
1249 }
1250 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1251 /** Renders a filled, bounding box for the given string as rendered via drawString.
1252 @param aString A string to render
1253 @param aFont The font to set the default with
1254 @param x The x coordinate at which to render the first glyph
1255 @param y The x coordinate at which to render the first glyph
1256 @param stringColor The color with which to render the glyphs
1257 @param boxColor The color with which to render the BOX
1258 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1259 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1260 void drawStringBox(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc);
1261 void drawStringBox(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc) {
1262 drawStringBox(aString, aFont, real2intX(x), real2intY(y), stringColor, boxColor, cex, spc);
1263 }
1264 //@}
1265
1266 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1267 /** @name File Reading and Writing Methods */
1268 //@{
1269 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1270 /** Is libTIFF supported -- that is: will the readTIFFfile() method do anything?
1271 Note that readTIFFfile() is the only method that needs libTIFF. In particular, writeTIFFfile() works without libTIFF. */
1272 bool supportLibTIFF();
1273 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1274 /** If the libTIFF library was found at build time, this function will read a TIFF file into current ramCanvas object.
1275
1276 If libTIFF is not supported, then this function returns 32. You can test if this method works via the supportLibTIFF() method.
1277
1278 Notable features:
1279 - Arbitrary TIFF image file types are converted to 24-bit RGB when aRamCanvas is of type ramCanvas3c8b
1280 - Note aRamCanvas must be of type ramCanvas3c8b -- ramCanvas4c8b is not good enough.
1281 - Reasonable conversions are made in other cases.
1282 - if aRamCanvas has fewer channels than the TIFF file, then extra channels in the TIFF file are ignored
1283 - if aRamCanvas has more channels than the TIFF file, then extra channels of aRamCanvas are set to black
1284 - 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)
1285 - Some effort is taken to do the right thing with respect to aRamCanvas axis orientation
1286
1287 @param fileName The file name from which to read data from.
1288 @retval 0 Image file loaded successfully
1289 @retval 1 File open (TIFFOpen) failure
1290 @retval 2 File missing TIFF tag: IMAGEWIDTH
1291 @retval 3 File missing TIFF tag: IMAGELENGTH
1292 @retval 4 File missing TIFF tag: SAMPLESPERPIXEL
1293 @retval 5 File missing TIFF tag: PLANARCONFIG
1294 @retval 6 File missing TIFF tag: PHOTOMETRIC
1295 @retval 7 File missing TIFF tag: BITSPERSAMPLE
1296 @retval 8 File of zero width
1297 @retval 9 File of zero height
1298 @retval 10 Allocation failed (temp image buffer)
1299 @retval 11 Read (TIFFReadRGBAImage) failure
1300 @retval 12 Canvas Allocation failed (insufficient width)
1301 @retval 14 Canvas Allocation failed (insufficient height)
1302 @retval 15 TIFF bps not 8, 16, 32, or 64
1303 @retval 16 Allocation failed (scan line buffer)
1304 @retval 17 Read (TIFFReadScanline) failure
1305 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1306 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1307 @retval 20 File and ramCanvas channel depth differ
1308 @retval 21 File and ramCanvas channel format (int vs float) differ
1309 @retval 22 Planar configuration is invalid (not 1 or 2)
1310 @retval 23 Tiled images are not supported
1311 @retval 24 PHOTOMETRIC_PALETTE not supported
1312 @retval 32 TIFF read support not provided in this compile */
1313 int readTIFFfile(std::string fileName);
1314 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1315 /** Write a TIFF format image file. Respects integer coordinate system orientation.
1316
1317 Why TIFF? TIFF is both broadly supported and flexible enough to represent almost every ramCanvas image type perfectly.
1318
1319 Use Cases (In order of priority)
1320 - Write a bit perfect TIFF representation of ramCanvas images
1321 - Simultaneously convert any ramCanvas into 24-bit truecolor RGB and write the resulting TIFF
1322 - Do all the above while simultaneously applying a homogeneous image filter
1323
1324 Limitations
1325 - Channels must be no more than 64-bits wide
1326 - No more than 2^16-1 channels
1327 - Image width no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1328 - Image height no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1329 - Image row data size (numPixX * colorT::bitsPerChan * colorT::channelCount / 8) must be less than 2^32-1 bytes
1330 - Image data must be less than 2^32-1 bytes
1331
1332 Limitations for bit perfect (toTRU is NULL) files:
1333 - Channels must be uint8_t, uint16_t, uint32_t, uint64_t, float (32-bit), or double (64-bit)
1334
1335 @param fileName The file name to write data to
1336 @param pxFilter An pxFilter object instance
1337 @param markAlpha If an alpha channel is present, then mark it as such in the TIFF file.
1338 @return Status of I/O
1339 @retval 0 Everything seems to have worked
1340 @retval 2 Image channels are too shallow for TIFF format
1341 @retval 3 Image channels are too deep for TIFF format
1342 @retval 4 Image has too few channels for TIFF format
1343 @retval 5 Image has too many channels for TIFF format
1344 @retval 6 Image has too few columns for TIFF format
1345 @retval 7 Image has too many columns for TIFF format
1346 @retval 8 Image has too few rows for TIFF format
1347 @retval 9 Image has too few rows for TIFF format
1348 @retval 10 Image rows are too large (too much data) for TIFF format
1349 @retval 11 Image is too large (too much data) for TIFF format */
1350 template <class rcConT> int writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha = true);
1351 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1352 /** Simplified overload for writeTIFFfile() that only requires the filename. */
1353 int writeTIFFfile(std::string fileName, bool markAlpha = true);
1354 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1355 /** Write a 24-bit (8-bit per channel) RGB, TGA format graphics file. Respects integer coordinate system orientation.
1356
1357 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
1358 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
1359 function to dump out regular RGB images, but I suggest writeTIFFfile() for that.
1360
1361 Note TGA files are 8-bit files, and *_byte functions are used to convert channel values to 8-bit before being written.
1362
1363 @param fileName The file name name to write data to
1364 @return Status of I/O
1365 @retval 0 Everything seems to have worked
1366 @retval 1 File open failure
1367 @retval 6 Image of zero width
1368 @retval 7 Image too wide for TGA format (> 2^16-1)
1369 @retval 8 Image of zero height
1370 @retval 9 Image too tall for TGA format (> 2^16-1) */
1371 int writeTGAfile(std::string fileName);
1372 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1373 /** Read RAW file
1374
1375 @warning This function is experimental! Functionality and API are likely to change in the future.
1376
1377 @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
1378 good fix looks like
1379
1380 @retval 0 Image file loaded successfully
1381 @retval 1 File open failure
1382 @retval 2 NOT USED
1383 @retval 3 NOT USED
1384 @retval 4 NOT USED
1385 @retval 5 NOT USED
1386 @retval 6 NOT USED
1387 @retval 7 NOT USED
1388 @retval 8 File of zero width
1389 @retval 9 File of zero height
1390 @retval 10 NOT USED
1391 @retval 11 Read failure
1392 @retval 12 Canvas Allocation failed (insufficient width)
1393 @retval 14 Canvas Allocation failed (insufficient height)
1394 @retval 15 bps not 8, 16, 32, or 64
1395 @retval 16 NOT USED
1396 @retval 17 NOT USED
1397 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1398 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1399 @retval 20 File and ramCanvas channel depth differ
1400 @retval 21 File and ramCanvas channel format (int vs float) differ
1401 @retval 22 NOT USED
1402 @retval 23 File is signed integer or unsigned float
1403 @retval 24 File is missing MJRRAW magic number
1404 @retval 25 Image data read failure (file may have ended prematurely)
1405 @retval 26 Malformed header
1406 @retval 27 Image is too wide to be supported by ramCanvas
1407 @retval 28 Image is too tall to be supported by ramCanvas
1408 @retval 29 Error reading numbers in header
1409 @retval 32 NOT USED
1410 @retval 33 Image width missing from header
1411 @retval 34 Image height missing from header
1412 @retval 35 Image channel count missing from header
1413 @retval 36 Image channel depth missing from header */
1414 int readRAWfile(std::string fileName);
1415 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1416 /** Write a MJRRAW file. Respects integer coordinate system orientation.
1417
1418 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
1419 data visualization tools -- usually via a feature referred to as a raw importer. ImageMagick, VisIT, ParaView, and ImageJ all can read this type of
1420 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,
1421 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
1422 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.
1423 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
1424 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
1425 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:
1426 x, y, c, b, s, t, & i. The header is followed by the binary image.
1427
1428 Labels:
1429 - x: Number of pixels on X (horizontal axis) expressed as a zero padded, decimal integer
1430 - y: Number of pixels on Y (vertical axis) expressed as a zero padded, decimal integer
1431 - c: Number of channels expressed as a zero padded, decimal integer
1432 - b: Number of bits per channel expressed as a zero padded, decimal integer
1433 - s: Channel signdness (ignored for floating point channels)
1434 - UNS: Unsigned data. DEFAULT VALUE.
1435 - SGN: Signed data
1436 - t: Channel type
1437 - INT: Integral channels. DEFAULT VALUE.
1438 - FLT: Floating point channels
1439 - i: endianness
1440 - BIG: Big endian
1441 - LTL: Little endian
1442 - UNK: Unknown. DEFAULT VALUE. For read we assume file matches system running the code.
1443 - Currently reserved, but unused labels
1444 - p: Pixel format
1445 - MXL: Each pixel of the image is written in sequence. DEFAULT VALUE.
1446 - PLN: Each channel of the *image* is written in sequence.
1447 - BIT: For bit-masks with 8 bits packed in a byte.
1448 - z: Compression
1449 - 000: No compression. DEFAULT VALUE.
1450 - ZLB: Zlib.
1451 - GZP: Gzip.
1452
1453 Two headers that both specify a 256x128 image with 3 unsigned 8-bit integer channels encoded little endian:
1454
1455 MJRRAW
1456 256x128y3c8bUNSsINTtLTLi00000000000000000000000000000000000000000000000000000000000000000000
1457
1458 MJRRAW
1459 0000000000000000256x0000000000000000128y000000000000000000000000003c00000000008bSGNsINTtLTLi
1460
1461 @param fileName The file name name to write data to
1462 @param pxFilter An pxFilter object instance
1463 @retval 0 The write was successful.
1464 @retval 1 Could not open file. */
1465 template <class rcConT> int writeRAWfile(std::string fileName, rcConT pxFilter);
1466 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1467 /** Simplified overload for writeRAWfile() that only requires the filename. */
1468 int writeRAWfile(std::string fileName);
1469 //@}
1470
1471 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1472 /** @name Boolean Clip Test Methods */
1473 //@{
1474 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1475 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1476 @param x The x coordinate of the point to test
1477 @param y The y coordinate of the point to test
1478 @return Returns true if the point would be clipped. */
1479 inline int isCliped(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1480 inline int isCliped(intCrdT x, intCrdT y) const { return ((x < 0) || (y < 0) || (x >= numPixX) || (y >= numPixY)); }
1481 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1482 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1483 @param x The x coordinate of the point to test
1484 @param y The y coordinate of the point to test
1485 @return Returns true if the point would be not be clipped. */
1486 inline int isOnCanvas(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1487 inline int isOnCanvas(intCrdT x, intCrdT y) const { return ((x >= 0) && (y >= 0) && (x < numPixX) && (y < numPixY)); }
1488 //@}
1489
1490 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1491 /** @name Coordinate Conversions. */
1492 //@{
1493 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1494 /** Convert real x coordinate to integral x coordinate
1495 @param x The real x coordinate value to be converted.
1496 @return The integer x coordinate corresponding to the given x coordinate */
1497 intCrdT real2intX(fltCrdT x) const;
1498 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1499 /** Convert real y coordinate to integral y coordinate
1500 @param y The real y coordinate value to be converted.
1501 @return The integer y coordinate corresponding to the given y coordinate */
1502 intCrdT real2intY(fltCrdT y) const;
1503 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1504 /** Convert integral x coordinate to real x coordinate
1505 @param x The integer x coordinate value to be converted.
1506 @return The real x coordinate corresponding to the given x coordinate */
1507 fltCrdT int2realX(intCrdT x);
1508 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1509 /** Convert integral y coordinate to real y coordinate
1510 @param y The integer y coordinate value to be converted.
1511 @return The real y coordinate corresponding to the given y coordinate */
1512 fltCrdT int2realY(intCrdT y);
1513 //@}
1514
1515 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1516 /** @name Coordinate Pair Conversions. */
1517 //@{
1518 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1519 /** Convert real x & y coordinates to integer x & y coordinates
1520 @param x The integer x coordinate value to be converted.
1521 @param y The integer y coordinate value to be converted.
1522 @return The real x & y coordinates corresponding to the given integer x & y coordinates */
1523 inline pointFltType int2real(intCrdT x, intCrdT y) { return point2d(int2realX(x), int2realY(y)); }
1524 /** Convert integer x & y coordinates to real x & y coordinates
1525 @param x The real x coordinate value to be converted.
1526 @param y The real y coordinate value to be converted.
1527 @return The integer x & y coordinates corresponding to the given real x & y coordinates */
1528 inline pointIntType real2int(intCrdT x, intCrdT y) { return point2d(real2intX(x), real2intY(y)); }
1529 //@}
1530
1531 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1532 /** @name Pixel Corner Coordinates.
1533 */
1534 //@{
1535 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1536 /** Given integer x coordinate, produce real x coordinate for one of the pixel's edge.
1537 @param x The integer x coordinate value to be converted.
1538 @param side The integer x coordinate of the corner -- should be 0 (lower) or 1 (upper).
1539 @return The real x & y coordinates corresponding to the requested corner */
1540 inline fltCrdT int2realSideX(intCrdT x, int side) { return int2realX(x)+pixWidX/(side ? static_cast<fltCrdT>(2.0) : static_cast<fltCrdT>(-2.0)); }
1541 /** Given integer y coordinate, produce real y coordinate for one of the pixel's edge.
1542 @param y The integer y coordinate value to be converted.
1543 @param side The integer y coordinate of the corner -- should be 0 (lower) or 1 (upper).
1544 @return The real y coordinates corresponding to the requested side */
1545 inline fltCrdT int2realSideY(intCrdT y, int side) { return int2realY(y)+pixWidY/(side ? static_cast<fltCrdT>(2.0) : static_cast<fltCrdT>(-2.0)); }
1546 /** Given integer x & y coordinates, produce real x & y coordinates for one of the pixel's corners.
1547 @param x The integer x coordinate value to be converted.
1548 @param y The integer y coordinate value to be converted.
1549 @param sideX The integer x coordinate of the corner -- should be 0 (lower) or 1 (upper).
1550 @param sideY The integer y coordinate of the corner -- should be 0 (lower) or 1 (upper).
1551 @return The real x & y coordinates corresponding to the requested corner */
1552 inline pointFltType int2realCorner(intCrdT x, intCrdT y, int sideX, int sideY) {return point2d(int2realSideX(x, sideX), int2realSideY(y, sideY)); }
1553 /** Given integer x & y coordinates and a corner index, produce real x & y coordinates for one of the pixel's corners.
1554 @param x The integer x coordinate value to be converted.
1555 @param y The integer y coordinate value to be converted.
1556 @param cornerIndex Corner index. 0 => (0, 0); 1 => (0, 1); 2 => (1, 0); 3 => (1, 1);
1557 @return The real x & y coordinates corresponding to the requested corner */
1558 inline pointFltType int2realCorner(intCrdT x, intCrdT y, int cornerIndex) { return int2realCorner(x, y, (cornerIndex >> 1), (cornerIndex & 1)); }
1559 //@}
1560
1561 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1562 /** @name Coordinate Delta Conversions. */
1563 //@{
1564 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1565 /** Convert real distance on the x coordinate axis to an integral distance
1566 @param x The real delta x to be converted
1567 @return integer delta x */
1568 inline intCrdT realDelta2intX(fltCrdT x) const { return static_cast<intCrdT>(static_cast<fltCrdT>(x)/pixWidX); }
1569 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1570 /** Convert real distance on the y coordinate axis to an integral distance
1571 @param y The real delta y to be converted
1572 @return integer delta y */
1573 inline intCrdT realDelta2intY(fltCrdT y) const { return static_cast<intCrdT>(static_cast<fltCrdT>(y)/pixWidY); }
1574 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1575 /** Convert integral distance on the x coordinate to a real distance
1576 @param x The real x coordinate value to be converted.
1577 @return The integer x coordinate corresponding to the given x coordinate */
1578 inline fltCrdT intDelta2realX(intCrdT x) const { return static_cast<fltCrdT>(x)*pixWidX; }
1579 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1580 /** Convert integral distance on the y coordinate to a real distance
1581 @param y real y coordinate value to be converted.
1582 @return The integer y coordinate corresponding to the given y coordinate */
1583 inline fltCrdT intDelta2realY(intCrdT y) const { return static_cast<fltCrdT>(y)*pixWidY; }
1584 //@}
1585
1586 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1587 /** @name Orientation of Real Coordinate Systems */
1588 //@{
1589 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1590 /** Get the real X axis orientation
1591 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1592 inline realAxisOrientation getRealAxOrientationX() { return realAxOrientationX; }
1593 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1594 /** Set the real X axis orientation
1595 @param orientation The orientation (INVERTED or NATURAL)*/
1596 inline void setRealAxOrientationX(realAxisOrientation orientation) { realAxOrientationX = orientation; }
1597 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1598 /** Get the real Y axis orientation
1599 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1600 inline realAxisOrientation getRealAxOrientationY() { return realAxOrientationX; }
1601 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1602 /** Set the real Y axis orientation
1603 @param orientation The orientation (INVERTED or NATURAL) */
1604 inline void setRealAxOrientationY(realAxisOrientation orientation) { realAxOrientationY = orientation; }
1605 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1606 /** Set the real axis orientation to default (NATURAL for both X and Y axes) */
1607 inline void setRealAxisDefaultOrientation() { setRealAxOrientationX(realAxisOrientation::NATURAL); setRealAxOrientationY(realAxisOrientation::NATURAL); }
1608 //@}
1609
1610 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1611 /** @name Drawing Mode */
1612 //@{
1613 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1614 /** Get the current drawing mode.
1615 @return The drawing mode */
1616 inline drawModeType getDrawMode() { return drawMode; }
1617 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1618 /** Set the current drawing mode
1619 NOOP if enableDrawModes is false.
1620 @param newDrawMode The drawing mode */
1621 inline void setDrawMode(drawModeType newDrawMode) { if constexpr (enableDrawModes) drawMode = newDrawMode; }
1622 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1623 /** Set the default draw mode */
1624 inline void setDefaultDrawMode() { setDrawMode(drawModeType::SET); }
1625 //@}
1626
1627 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1628 /** @name Orientation of Integer Coordinate Systems */
1629 //@{
1630 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1631 /** Get the integer X axis orientation
1632 @return NATURAL means increasing to the right. */
1633 inline intAxisOrientation getIntAxOrientationX() { return intAxOrientationX; }
1634 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1635 /** Is the integer X axis NATURAL?
1636 @return true means increasing to the right. */
1637 inline bool isIntAxOrientationNaturalX() { return (intAxOrientationX == intAxisOrientation::NATURAL); }
1638 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1639 /** Set the integer X axis orientation
1640 @param orientation The orientation (INVERTED or NATURAL) */
1641 inline void setIntAxOrientationX(intAxisOrientation orientation) { intAxOrientationX = orientation; }
1642 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1643 /** Get the integer Y axis orientation
1644 @return NATURAL means increasing in the upward direction. */
1645 inline bool isIntAxOrientationNaturalY() { return (intAxOrientationY == intAxisOrientation::NATURAL); }
1646 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1647 /** Is the integer Y axis orientation NATURAL?
1648 @return NATURAL means increasing in the upward direction. */
1649 inline intAxisOrientation getIntAxOrientationY() { return intAxOrientationY; }
1650 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1651 /** Set the integer Y axis orientation
1652 @param orientation The orientation (INVERTED or NATURAL) */
1653 inline void setIntAxOrientationY(intAxisOrientation orientation) { intAxOrientationY = orientation; }
1654 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1655 /** Set the integer axis orientation to default (NATURAL for both X and Y axes) */
1656 inline void setIntAxisDefaultOrientation() { setIntAxOrientationX(intAxisOrientation::NATURAL); setIntAxOrientationY(intAxisOrientation::NATURAL); }
1657 //@}
1658
1659 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1660 /** @name Accessor Methods */
1661 //@{
1662 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1663 /** @return The number of pixels in the x direction. */
1664 inline intCrdT getNumPixX() const { return numPixX; }
1665 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1666 /** @return The number of pixels in the y direction. */
1667 inline intCrdT getNumPixY() const { return numPixY; }
1668 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1669 /** Returns a pointer to the raw pixel store.
1670 This generally violates the ramCanvasTpl object interface; however, this may be required for performance.
1671 @return The number a pointer to the raw pixel store. */
1672 colorT *getPixels() { return pixels; }
1673 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1674 /** Return a clone (a copy) of the raw pixel store.
1675 This function copies the internal pixel store and returns a pointer to this copy.
1676 @return Pointer to a copy of the raw pixel store. */
1677 colorT *clonePixels();
1678 //@}
1679
1680 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1681 /** @name Real Coordinate Accessor Methods */
1682 //@{
1683 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1684 fltCrdT getMinRealX() { return minRealX; } //!< x coord of min (real coord)
1685 fltCrdT getMaxRealX() { return maxRealX; } //!< x coord of max (real coord)
1686 fltCrdT getMinRealY() { return minRealY; } //!< y coord of min (real coord)
1687 fltCrdT getMaxRealY() { return maxRealY; } //!< y coord of max (real coord)
1688 fltCrdT getPixWidX() { return pixWidX; } //!< Width of a pixel (real coord)
1689 fltCrdT getPixWidY() { return pixWidY; } //!< Height of a pixel (real coord)
1690 fltCrdT getCanvasWidX() { return canvasWidX; } //!< Width of the display (real coord)
1691 fltCrdT getCanvasWidY() { return canvasWidY; } //!< height of the display(real coord)
1692 fltCrdT getCanvasWidD() { return std::hypot(canvasWidX, canvasWidY); } //!< Width of the display (real coord)
1693 //@}
1694
1695 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1696 /** @name Pixel Value Accessor Methods */
1697 //@{
1698 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1699 /** Returns a copy of the color at the given coordinates. */
1700 colorT getPxColor(intCrdT x, intCrdT y) const;
1701 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1702 /** @overload */
1703 inline colorT getPxColor(fltCrdT x, fltCrdT y) const { return getPxColor(real2intX(x), real2intY(y)); }
1704 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1705 /** @overload */
1706 inline colorT getPxColor(pointIntType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1707 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1708 /** @overload */
1709 inline colorT getPxColor(pointFltType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1710 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1711 /** Returns a copy of the color at the given coordinates wrapping x & y if out of range. */
1712 inline colorT getPxColorWrap(intCrdT x, intCrdT y) const { return getPxColorNC(mjr::math::ivl::wrapCO(x, numPixX), mjr::math::ivl::wrapCO(y, numPixY)); }
1713 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1714 /** @overload */
1715 inline colorT getPxColorWrap(fltCrdT x, fltCrdT y) const { return getPxColorWrap(real2intX(x), real2intY(y)); }
1716 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1717 /** @overload */
1718 inline colorT getPxColorWrap(pointIntType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y); }
1719 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1720 /** @overload */
1721 inline colorT getPxColorWrap(pointFltType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y); }
1722 //@}
1723
1724 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1725 /** @name Pixel Channel Value Accessor Methods. */
1726 //@{
1727 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1728 /** Returns a copy of the color channel value at the given coordinates wrapping x & y if out of range. */
1729 template <int chanNum>
1730 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1731 inline colorChanType getPxColorChanWrap(intCrdT x, intCrdT y) const { return getPxColorWrap(x, y).getChanNC(chanNum); }
1732 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1733 /** @overload */
1734 template <int chanNum>
1735 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1736 inline colorChanType getPxColorChanWrap(fltCrdT x, fltCrdT y) const { return getPxColorWrap(real2intX(x), real2intY(y)).getChanNC(chanNum); }
1737 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1738 /** @overload */
1739 template <int chanNum>
1740 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1741 inline colorChanType getPxColorChanWrap(pointIntType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y).getChanNC(chanNum); }
1742 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1743 /** @overload */
1744 template <int chanNum>
1745 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1746 inline colorChanType getPxColorChanWrap(pointFltType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y).getChanNC(chanNum); }
1747 //@}
1748
1749 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1750 /** @name Pixel Value Accessor with Interpolation Methods */
1751 //@{
1752 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1753 /** Returns the interpolated color value at the the given coordinates using the given interpolation method.
1754 @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)
1755 @param y The y coordinate
1756 @param interpMethod The interpolation method (default: interpolationType::BILINEAR)
1757 @return Interpolated color value */
1758 colorT getPxColorInterpolate(double x, double y, interpolationType interpMethod = interpolationType::BILINEAR);
1759 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1760 /** Returns the bilinear interpolated color value at the the given coordinates.
1761 @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)
1762 @param y The y coordinate
1763 @return Interpolated color value */
1764 colorT getPxColorInterpBLin(double x, double y);
1765 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1766 /** Returns the truncated interpolated color value at the the given coordinates.
1767 @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)
1768 @param y The y coordinate
1769 @return Interpolated color value */
1770 colorT getPxColorInterpTrunc(double x, double y);
1771 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1772 /** Returns the nearest neighbor interpolated color value at the the given coordinates.
1773 @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)
1774 @param y The y coordinate
1775 @return Interpolated color value */
1776 colorT getPxColorInterpNear(double x, double y);
1777 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1778 /** Returns the average 4 interpolated color value at the the given coordinates.
1779 @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)
1780 @param y The y coordinate
1781 @return Interpolated color value */
1782 colorT getPxColorInterpAvg4(double x, double y);
1783 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1784 /** Returns the average 9 interpolated color value at the the given coordinates.
1785 @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)
1786 @param y The y coordinate
1787 @return Interpolated color value */
1788 colorT getPxColorInterpAvg9(double x, double y);
1789 //@}
1790
1791 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1792 /** @name NC stands for No Checks and No Clipping */
1793 /** 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
1794 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
1795 very careful code that handles clipping and error checking by itself -- a good line drawing algorithm for example. */
1796 //@{
1797 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1798 /** Draw a point with no clipping or bounds checking.
1799 @param x The x coordinate of the point to be drawn
1800 @param y The y coordinate of the point to be drawn
1801 @param color The color to draw the point. */
1802 void drawPointNC(intCrdT x, intCrdT y, colorArgType color);
1803 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1804 /** Get the default point to the specified coordinates with no clipping or bounds checking.
1805 @param x The x coordinate of the point
1806 @param y The y coordinate of the point */
1807 inline colorT getPxColorNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1808 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1809 /** Returns a reference to the color object for the given pixel with no clipping or bounds checking.
1810 @param x The x coordinate of the point
1811 @param y The y coordinate of the point
1812 @return Reference to the color object associated with the specified point */
1813 inline colorT& getPxColorRefNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1814 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1815 /** Draw a horizontal line with no clipping or bounds checking.
1816 @param xMin The MINIMUM x coordinate of the line to be drawn
1817 @param xMax The MAXIMUM x coordinate of the line to be drawn
1818 @param yConst The y coordinate at which the line is to be drawn
1819 @param color The color to draw the line */
1820 inline void drawHorzLineNC(intCrdT xMin, intCrdT xMax, intCrdT yConst, colorArgType color) { for(intCrdT x=xMin;x<=xMax;x++) drawPointNC(x, yConst, color); }
1821 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1822 /** Draw a vertical line with no clipping or bounds checking.
1823 @param yMin The MINIMUM y coordinate of the line to be drawn
1824 @param yMax The MAXIMUM y coordinate of the line to be drawn
1825 @param xConst The x coordinate at which the line is to be drawn
1826 @param color The color to draw the line */
1827 inline void drawVertLineNC(intCrdT yMin, intCrdT yMax, intCrdT xConst, colorArgType color) { for(intCrdT y=yMin;y<=yMax;y++) drawPointNC(xConst, y, color); }
1828 //@}
1829
1830 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1831 /** @name S stands for Simple */
1832 //@{
1833 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1834 /** Draw a point without any special drawing options.
1835 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
1836 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
1837 careful code that handles clipping and error checking and drawing options by itself -- an image filter algorithm for example. Note that enableDrawModes
1838 is ignored.
1839 @param x The x coordinate of the point
1840 @param y The y coordinate of the point
1841 @param color The color with which to draw the point */
1842 inline void drawPointS(intCrdT x, intCrdT y, colorArgType color) { pixels[numPixX * y + x] = color; }
1843 //@}
1844
1845 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1846 /** @name Canvas Level Colorization.
1847 These are tools designed to make things like escape time fractals very easy to create.
1848
1849 @warning These functions are experimental! Functionality and API are likely to change in the future.
1850
1851 */
1852 //@{
1853 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1854 void colorizeFltCanvas(std::function<colorT (fltCrdT, fltCrdT)> cFun);
1855 void colorizeFltCanvas(std::function<colorT (pointFltType)> cFun);
1856
1857 void colorizeIntCanvas(std::function<colorT (intCrdT, intCrdT)> cFun);
1858 void colorizeIntCanvas(std::function<colorT (pointIntType)> cFun);
1859 //@}
1860
1861 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1862 /** @name Canvas Level Statistical Computation.
1863 */
1864 //@{
1865 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1866 intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
1867 intCrdT retCount = 0;
1868 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
1869 if(x1 > x2)
1870 std::swap(x1, x2);
1871 if(y1 > y2)
1872 std::swap(y1, y2);
1873 for(intCrdT y=y1;y<=y2;y++)
1874 for(intCrdT x=x1;x<=x2;x++)
1875 //if ( !(getPxColor(x, y).isBlack()))
1876 if ( !(getPxColorRefNC(x, y).isBlack()))
1877 retCount++;
1878 }
1879 return(retCount);
1880 }
1881 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1883 return statNumNonZeroPixels(0, 0, numPixX-1, numPixY-1);
1884 }
1885 //@}
1886 };
1887
1888 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1889 // Constructor
1890 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1891 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1893 newIntCoordsNC(-1, -1);
1894 newRealCoords(0.0, 0.0, 0.0, 0.0);
1895 pixels = NULL;
1896 pixelsE = NULL;
1897 setRealAxisDefaultOrientation();
1898 setIntAxisDefaultOrientation();
1899 setDefaultDrawMode();
1900 }
1901
1902 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1903 // Copy Constructor
1904 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1905 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1907 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1908 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1909 pixels = new colorT[theCanvas.numPixX * theCanvas.numPixY];
1910 pixelsE = pixels + (theCanvas.numPixX * theCanvas.numPixY);
1911 realAxOrientationX = theCanvas.realAxOrientationX;
1912 realAxOrientationY = theCanvas.realAxOrientationY;
1913 intAxOrientationX = theCanvas.intAxOrientationX;
1914 intAxOrientationY = theCanvas.intAxOrientationY;
1915 drawMode = theCanvas.drawMode;
1916 for(intCrdT y=0; y<numPixY; y++)
1917 for(intCrdT x=0; x<numPixX; x++)
1918 getPxColorRefNC(x, y) = theCanvas.getPxColorRefNC(x, y);
1919 }
1920
1921 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1922 // Move constructor
1923 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1924 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1926 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1927 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1928 realAxOrientationX = theCanvas.realAxOrientationX;
1929 realAxOrientationY = theCanvas.realAxOrientationY;
1930 intAxOrientationX = theCanvas.intAxOrientationX;
1931 intAxOrientationY = theCanvas.intAxOrientationY;
1932 drawMode = theCanvas.drawMode;
1933 pixels = theCanvas.pixels;
1934 pixelsE = theCanvas.pixelsE;
1935 }
1936
1937////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1938// Move assignment operator
1939 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1940 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1943 if (this != &theCanvas) {
1944 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1945 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1946 realAxOrientationX = theCanvas.realAxOrientationX;
1947 realAxOrientationY = theCanvas.realAxOrientationY;
1948 intAxOrientationX = theCanvas.intAxOrientationX;
1949 intAxOrientationY = theCanvas.intAxOrientationY;
1950 drawMode = theCanvas.drawMode;
1951 pixels = theCanvas.pixels;
1952 pixelsE = theCanvas.pixelsE;
1953 }
1954 return *this;
1955 }
1956
1957////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1958 // Normal Constructor
1959 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1960 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1961 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
1962 newIntCoordsNC(numPixX_p, numPixY_p);
1963 newRealCoords(minRealX_p, maxRealX_p, minRealY_p, maxRealY_p);
1964 pixels = new colorT[numPixX * numPixY];
1965 pixelsE = pixels + (numPixX * numPixY);
1966 setRealAxisDefaultOrientation();
1967 setIntAxisDefaultOrientation();
1968 setDefaultDrawMode();
1969 clrCanvasToBlack();
1970 }
1971
1972////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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)
1976 if(pixels != NULL) {
1977 delete[] pixels;
1978 pixels = NULL;
1979 }
1980 }
1981
1982////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1983 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1984 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1985 inline void
1987 if(numPixX_p > intCrdMax) {
1988 throw std::invalid_argument("newIntCoordsNC: numPixX_p argument too large.");
1989 } else if (numPixY_p > intCrdMax) {
1990 throw std::invalid_argument("newIntCoordsNC: numPixY_p argument too large.");
1991 } else {
1992 numPix = numPixX_p * numPixY_p;;
1993 numPixX = numPixX_p;
1994 numPixY = numPixY_p;
1995 }
1996 }
1997
1998////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1999 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2000 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2001 inline void
2002 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
2003 if(minRealX_p > maxRealX_p) {
2004 throw std::invalid_argument("newRealCoords: minRealX_p > maxRealX_p.");
2005 } else if (minRealY_p > maxRealY_p) {
2006 throw std::invalid_argument("newRealCoords: minRealY_p > maxRealY_p.");
2007 } else {
2008 minRealX = minRealX_p;
2009 maxRealX = maxRealX_p;
2010 minRealY = minRealY_p;
2011 maxRealY = maxRealY_p;
2012 updRealCoords();
2013 }
2014 }
2015
2016////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2017 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2018 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2019 inline void
2021 canvasWidX = maxRealX - minRealX;
2022 canvasWidY = maxRealY - minRealY;
2023 pixWidX = (numPixX == 0 ? 0 : canvasWidX / numPixX); // This will cause /0 later if anyone tries to use a coordinate conversion
2024 pixWidY = (numPixY == 0 ? 0 : canvasWidY / numPixY); // This will cause /0 later if anyone tries to use a coordinate conversion
2025 }
2026
2027////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2028 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2029 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2030 inline void
2032 for(intCrdT y=0; y<numPixY; y++)
2033 for(intCrdT x=0; x<numPixX; x++)
2034 getPxColorRefNC(x, y).setChanToMin(chan);
2035 }
2036
2037////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2038 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2039 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2040 inline void
2042 for(intCrdT y=0; y<numPixY; y++)
2043 for(intCrdT x=0; x<numPixX; x++)
2044 getPxColorRefNC(x, y).setChanToMax(chan);
2045 }
2046
2047////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2048 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2049 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2050 inline void
2052 ////// Diffrent ways to do it -- unless otherwise noted, all of them are about the same performance with GCC if colorT has a fast mask
2053
2054 //// Use std:memset
2055 // std::memset((void*)pixels, 0, numPix*sizeof(colorT));
2056
2057 //// Use std::fill
2058 // colorT black;
2059 // black.setToBlack();
2060 // std::fill(pixels, pixelsE, black);
2061
2062 //// Loop over pixel array
2063 // for(colorT* p=pixels; p<pixelsE; p++)
2064 // p->setToBlack();
2065
2066 //// loop over x & y coordinates
2067 for(intCrdT y=0; y<numPixY; y++)
2068 for(intCrdT x=0; x<numPixX; x++)
2069 getPxColorRefNC(x, y).setToBlack();
2070
2071 //// Call clrCanvas with black (this one is *way* slower)
2072 // clrCanvas(colorT(colorCornerEnum::BLACK));
2073 }
2074
2075////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2076 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2077 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2078 inline void
2080 for(intCrdT y=0; y<numPixY; y++)
2081 for(intCrdT x=0; x<numPixX; x++)
2082 getPxColorRefNC(x, y).setToWhite();
2083 }
2084
2085////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2086 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2087 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2088 inline void
2092
2093////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2094 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2095 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2096 inline void
2098 for(intCrdT y=0; y<numPixY; y++)
2099 for(intCrdT x=0; x<numPixX; x++)
2100 drawPointS(x, y, color);
2101 }
2102
2103////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2104 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2105 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2106 void
2108 colorChanType cmin = colorT::maxChanVal;
2109 colorChanType cmax = colorT::minChanVal;
2110 for(intCrdT y=0;y<numPixY;y++) {
2111 for(intCrdT x=0;x<numPixX;x++) {
2112 colorT daColor = getPxColorNC(x, y);
2113 colorChanType curMin = daColor.getMinC();
2114 colorChanType curMax = daColor.getMaxC();
2115 if(curMax > cmax)
2116 cmax = curMax;
2117 if(curMin < cmin)
2118 cmin = curMin;
2119 }
2120 }
2121 if(cmax-cmin > 0) {
2122 double c = 1.0 * static_cast<double>(colorT::maxChanVal-colorT::minChanVal) / static_cast<double>(cmax-cmin);
2123 double b = static_cast<double>(colorT::maxChanVal) - 1.0 * c * static_cast<double>(cmax);
2124 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScale, c, b);
2125 }
2126 }
2127
2128////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2129 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2130 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2131 void
2133 colorT cmin; cmin.setChans(cmin.maxChanVal);
2134 colorT cmax; cmax.setChans(cmin.minChanVal);
2135 for(intCrdT y=0;y<numPixY;y++) {
2136 for(intCrdT x=0;x<numPixX;x++) {
2137 colorT daColor = getPxColorNC(x, y);
2138 cmin.tfrmMin(daColor);
2139 cmax.tfrmMax(daColor);
2140 }
2141 }
2142 colorChanType absCompMin = cmin.getMinC();
2143 colorChanType absCompMax = cmax.getMaxC();
2144 if(absCompMax-absCompMin > 0) {
2145 double rc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getRed()-cmin.getRed());
2146 double rb = cmin.maxChanVal - 1.0*rc*cmax.getRed();
2147 double gc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getGreen()-cmin.getGreen());
2148 double gb = cmin.maxChanVal - 1.0*gc*cmax.getGreen();
2149 double bc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getBlue()-cmin.getBlue());
2150 double bb = cmin.maxChanVal - 1.0*bc*cmax.getBlue();
2151 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScaleRGB, rc, rb, gc, gb, bc, bb);
2152 }
2153 }
2154
2155////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2156 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2157 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2158 inline void
2160 for(intCrdT y=0; y<numPixY; y++)
2161 for(intCrdT x=0; x<numPixX; x++)
2162 f(getPxColorRefNC(x, y));
2163 }
2164
2165////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2166 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2167 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2168 inline void
2170 for(intCrdT y=0; y<numPixY; y++)
2171 for(intCrdT x=0; x<numPixX; x++)
2172 (getPxColorRefNC(x, y).*HPT)();
2173 }
2174
2175////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2176 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2177 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2178 inline void
2180 for(intCrdT y=0; y<numPixY; y++)
2181 for(intCrdT x=0; x<numPixX; x++)
2182 (getPxColorRefNC(x, y).*HPT)(arg1);
2183 }
2184
2185////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2186 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2187 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2188 inline void
2189 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT arg1, colorT arg2) {
2190 for(intCrdT y=0; y<numPixY; y++)
2191 for(intCrdT x=0; x<numPixX; x++)
2192 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2193 }
2194
2195////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2196 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2197 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2198 inline void
2199 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3) {
2200 for(intCrdT y=0; y<numPixY; y++)
2201 for(intCrdT x=0; x<numPixX; x++)
2202 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2203 }
2204
2205////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2206 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2207 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2208 inline void
2209 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3, colorT arg4) {
2210 for(intCrdT y=0; y<numPixY; y++)
2211 for(intCrdT x=0; x<numPixX; x++)
2212 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2213 }
2214
2215////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2216 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2217 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2218 inline void
2220 for(intCrdT y=0; y<numPixY; y++)
2221 for(intCrdT x=0; x<numPixX; x++)
2222 (getPxColorRefNC(x, y).*HPT)(arg1);
2223 }
2224
2225////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2226 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2227 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2228 inline void
2229 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int arg1, int arg2) {
2230 for(intCrdT y=0; y<numPixY; y++)
2231 for(intCrdT x=0; x<numPixX; x++)
2232 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2233 }
2234
2235////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2236 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2237 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2238 inline void
2239 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int arg1, int arg2, int arg3) {
2240 for(intCrdT y=0; y<numPixY; y++)
2241 for(intCrdT x=0; x<numPixX; x++)
2242 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2243 }
2244
2245////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2246 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2247 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2248 inline void
2249 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int arg1, int arg2, int arg3, int arg4) {
2250 for(intCrdT y=0; y<numPixY; y++)
2251 for(intCrdT x=0; x<numPixX; x++)
2252 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2253 }
2254
2255////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2256 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2257 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2258 inline void
2260 for(intCrdT y=0; y<numPixY; y++)
2261 for(intCrdT x=0; x<numPixX; x++)
2262 (getPxColorRefNC(x, y).*HPT)(arg1);
2263 }
2264
2265////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2266 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2267 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2268 inline void
2269 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double arg1, double arg2) {
2270 for(intCrdT y=0; y<numPixY; y++)
2271 for(intCrdT x=0; x<numPixX; x++)
2272 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2273 }
2274
2275////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2276 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2277 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2278 inline void
2279 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double arg1, double arg2, double arg3) {
2280 for(intCrdT y=0; y<numPixY; y++)
2281 for(intCrdT x=0; x<numPixX; x++)
2282 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2283 }
2284
2285////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2286 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2287 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2288 inline void
2289 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double),
2290 double arg1, double arg2, double arg3, double arg4) {
2291 for(intCrdT y=0; y<numPixY; y++)
2292 for(intCrdT x=0; x<numPixX; x++)
2293 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2294 }
2295
2296////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2297 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2298 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2299 inline void
2300 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double),
2301 double arg1, double arg2, double arg3, double arg4, double arg5) {
2302 for(intCrdT y=0; y<numPixY; y++)
2303 for(intCrdT x=0; x<numPixX; x++)
2304 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5);
2305 }
2306
2307////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2308 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2309 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2310 inline void ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double),
2311 double arg1, double arg2, double arg3, double arg4, double arg5, double arg6) {
2312 for(intCrdT y=0; y<numPixY; y++)
2313 for(intCrdT x=0; x<numPixX; x++)
2314 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5, arg6);
2315 }
2316
2317////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2318 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2319 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2321 const ramCanvasTpl &theCanvas,
2322 intCrdT trgX, intCrdT trgY,
2323 intCrdT wide, intCrdT tall,
2324 intCrdT srcX, intCrdT srcY) {
2325 // Figure out real default width
2326 if(wide < 0)
2327 wide = numPixX-trgX;
2328
2329 // Make sure wide is not wider than current canvas.
2330 if(wide > (numPixX-srcX))
2331 wide = theCanvas.getNumPixX()-srcX;
2332
2333 // Make sure wide is not wider than given canvas.
2334 if(wide > (theCanvas.getNumPixX()-srcX))
2335 wide = theCanvas.getNumPixX()-srcX;
2336
2337 // Figure out real default tall
2338 if(tall < 0)
2339 tall = numPixY-srcY;
2340
2341 // Make sure tall is not taller than current canvas.
2342 if(tall > (numPixY-srcY))
2343 tall = numPixY-srcY;
2344
2345 // Make sure tall is not taller than given canvas.
2346 if(tall > (theCanvas.getNumPixY()-srcY))
2347 tall = theCanvas.getNumPixY()-srcY;
2348
2349 intCrdT xMax = trgX+wide;
2350 intCrdT yMax = trgY+tall;
2351 for(intCrdT y=trgY, ys=srcY; y<yMax; y++, ys++)
2352 for(intCrdT x=trgX, xs=srcX; x<xMax; x++, xs++)
2353 (getPxColorRefNC(x, y).*HPT)(theCanvas.getPxColor(xs, ys));
2354 }
2355
2356////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2357 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2358 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2359 void
2360 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
2361 moveTo(x2, y2); // Do this first
2362 intCrdT x, y;
2363 if(y1 == y2) { // slope = 0
2364 if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
2365 return;
2366 if(x1 > x2) // . Fix point ordering
2367 std::swap(x1, x2);
2368 if(x1 < 0) // . Clip left
2369 x1 = 0;
2370 if(x2 >= numPixX) // . Clip right
2371 x2 = numPixX - 1;
2372 drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
2373 } else if(x1 == x2) { // slope = infinity
2374 if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
2375 return;
2376 if(y1 > y2) // . Fix point ordering
2377 std::swap(y1, y2);
2378 if(y1 < 0) // . Clip top
2379 y1 = 0;
2380 if(y2 >= numPixY) // . Clip bottom
2381 y2 = numPixY - 1;
2382 drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
2383 } else { // Slope is not infinity or 0...
2384 int dx, dy;
2385 if(x1 > x2) { // . Fix point ordering
2386 std::swap(x1, x2);
2387 std::swap(y1, y2);
2388 }
2389 dx = x2 - x1; // . Compute the slope
2390 dy = y2 - y1;
2391 if(dx == dy) { // . Slope = 1
2392 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
2393 return;
2394 if(x1 < 0) { // .. Clip left
2395 y1 = y1 - x1;
2396 x1 = 0;
2397 }
2398 if(y1 < 0) { // .. Clip top
2399 x1 = x1 - y1;
2400 y1 = 0;
2401 }
2402 if(x2 >= numPixX) { // .. Clip right
2403 y2 = y2 - (x2 - numPixX) - 1;
2404 x2 = numPixX - 1;
2405 }
2406 if(y2 >= numPixY) { // .. Clip bottom
2407 x2 = x2 - (y2 - numPixY) - 1;
2408 y2 = numPixY - 1;
2409 }
2410 for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
2411 drawPointNC(x, y, color);
2412 } else if(dx == -dy) { // . Slope = -1
2413 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
2414 return;
2415 if(x1 < 0) { // .. Clip left
2416 y1 = y1 + x1;
2417 x1 = 0;
2418 }
2419 if(x2 >= numPixX) { // .. Clip right
2420 y2 = y2 + (x2 - (numPixX - 1));
2421 x2 = numPixX - 1;
2422 }
2423 if(y2 < 0) { // .. Clip top
2424 x2 = x2 + y2;
2425 y2 = 0;
2426 }
2427 if(y1 >= numPixY) { // .. Clip bottom
2428 x1 = x1 + (y1 - (numPixY - 1));
2429 y1 = numPixY - 1;
2430 }
2431 for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
2432 drawPointNC(x, y, color);
2433 } else { // . Slope != 1, -1, 0, \infinity
2434 int s, dx2, dy2;
2435 dx2 = 2*dx;
2436 dy2 = 2*dy;
2437 if(dy > 0) { // .. Positive Slope
2438 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
2439 return;
2440 if(x1 < 0) { // ... Clip left
2441 y1 = (int)(1.0*y1-x1*dy/dx);
2442 x1 = 0;
2443 }
2444 if(y1 < 0) { // ... Clip top
2445 x1 = (int)(1.0*x1-y1*dx/dy);
2446 y1 = 0;
2447 }
2448 if(x2 >= numPixX) { // ... Clip right
2449 y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
2450 x2 = numPixX - 1;
2451 }
2452 if(y2 >= numPixY) { // ... Clip bottom
2453 x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
2454 y2 = numPixY - 1;
2455 }
2456// MJR TODO NOTE drawLine: We use drawPoint instead of drawPointNC, can we make an off canvas decesion instead? Similar case down below.
2457 if(dx > dy) { // ... 0 < Slope < 1
2458 s = dy2 - dx;
2459 x=x1;
2460 y=y1;
2461 while(x<=x2) { // .... Draw Line
2462 drawPoint(x, y, color);
2463 if(s < 0) {
2464 s += dy2;
2465 } else {
2466 y++;
2467 s += dy2 - dx2;
2468 }
2469 x++;
2470 }
2471 } else { // ... 1 < Slope < infinity
2472 s = dy - dx2;
2473 x=x1;
2474 y=y1;
2475 while(y<=y2) { // .... Draw Line
2476 drawPoint(x, y, color);
2477 if(s > 0) {
2478 s -= dx2;
2479 } else {
2480 x++;
2481 s += dy2 - dx2;
2482 }
2483 y++;
2484 }
2485 }
2486 } else { // .. Negative Slope
2487 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
2488 return;
2489 if(x1 < 0) { // ... Clip left
2490 y1 = (int)(1.0*y1-x1*dy/dx);
2491 x1 = 0;
2492 }
2493 if(y2 < 0) { // ... Clip top
2494 x2 = (int)(1.0*x2-y2*dx/dy);
2495 y2 = 0;
2496 }
2497 if(x2 >= numPixX) { // ... Clip right
2498 y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
2499 x2 = numPixX - 1;
2500 }
2501 if(y1 >= numPixY) { // ... Clip bottom
2502 x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
2503 y1 = numPixY - 1;
2504 }
2505 if(dx > -dy) { // ... 0 > Slope > -infinity
2506 s = dy2 + dx;
2507 x=x1;
2508 y=y1;
2509 while(x<=x2) { // .... Draw Line
2510 drawPoint(x, y, color);
2511 if(s > 0) {
2512 s += dy2;
2513 } else {
2514 y--;
2515 s += dy2 + dx2;
2516 }
2517 x++;
2518 }
2519 } else { // ... -1 > Slope > -inf
2520 s = dy + dx2;
2521 x=x1;
2522 y=y1;
2523 while(y>=y2) { // .... Draw Line
2524 drawPoint(x, y, color);
2525 if(s < 0) {
2526 s += dx2;
2527 } else {
2528 x++;
2529 s += dy2 + dx2;
2530 }
2531 y--;
2532 }
2533 }
2534 }
2535 }
2536 }
2537 }
2538
2539////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2540 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2541 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2542 void
2544 newIntCoordsNC(-1, -1);
2545 if(pixels != NULL) {
2546 delete[] pixels;
2547 pixels=NULL;
2548 pixelsE=NULL;
2549 }
2550 }
2551
2552////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2553 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2554 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2555 void
2556 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY) {
2557 freeCanvas();
2558 newIntCoordsNC(new_numPixX, new_numPixY);
2559 updRealCoords();
2560 if(new_pixels != NULL)
2561 pixels = new_pixels;
2562 if(pixels == NULL)
2563 pixelsE = NULL;
2564 else
2565 pixelsE = pixels+(new_numPixX * new_numPixY);
2566 }
2567
2568////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2569 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2570 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2571 void
2573 if((numPixX_p<=0) || (numPixY_p<=0)) {
2574 freeCanvas();
2575 } else {
2576 if( (numPixX_p!=numPixX) || (numPixY_p!=numPixY) ) {
2577 colorT *new_pixels = new colorT[numPixX_p * numPixY_p];
2578 rePointPixels(new_pixels, numPixX_p, numPixY_p);
2579 } else {
2580 // Don't really do anything as the new size is the same as the old size...
2581 }
2582 }
2583 }
2584
2585////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2586 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2587 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2588 void
2590 reallocCanvas(new_numPixX_p, new_numPixY_p);
2591 }
2592
2593////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2594 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2595 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2596 void
2597 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1, intCrdT y1, colorArgType color) {
2598 if( (new_numPixX_p != numPixX) || (new_numPixY_p != numPixY) ) {
2599
2600 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2601
2602 // Fill it up with the default color. Should only draw the ones that need it, but computers are fast...
2603 for(intCrdT y=0;y<new_numPixY_p;y++)
2604 for(intCrdT x=0;x<new_numPixX_p;x++)
2605 new_pixels[new_numPixX_p * (y) + (x)] = color;
2606
2607 intCrdT yMax = std::min(numPixY+y1, new_numPixY_p);
2608 intCrdT xMax = std::min(numPixX+x1, new_numPixX_p);
2609
2610 // Copy the old image to the new space.
2611 if ((x1 < new_numPixX_p) && (y1 < new_numPixY_p))
2612 for(intCrdT y=y1;y<yMax;y++)
2613 for(intCrdT x=x1;x<xMax;x++)
2614 new_pixels[new_numPixX_p * (y) + (x)] = getPxColor(x-x1, y-y1);
2615
2616 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2617 }
2618 }
2619
2620////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2621 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2622 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2623 void
2624 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
2625 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
2626 if(x1 > x2)
2627 std::swap(x1, x2);
2628 if(y1 > y2)
2629 std::swap(y1, y2);
2630 intCrdT xp, yp, x, y;
2631 intCrdT new_numPixX_p = x2-x1+1;
2632 intCrdT new_numPixY_p = y2-y1+1;
2633 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2634
2635 // Copy the old image to the new space.
2636 for(y=y1,yp=0;y<=y2;y++,yp++)
2637 for(x=x1,xp=0;x<=x2;x++,xp++)
2638 new_pixels[new_numPixX_p * yp + xp] = getPxColor(x, y);
2639
2640 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2641 }
2642 }
2643
2644////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2645 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2646 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2647 void
2649 for(intCrdT y=0; y<numPixY/2; y++)
2650 for(intCrdT x=0; x<numPixX; x++) {
2651 colorT aColor = getPxColor(x, numPixY-y-1);
2652 drawPointNC(x, numPixY-y-1, getPxColor(x, y));
2653 drawPointNC(x, y, aColor);
2654 }
2655 }
2656
2657////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2658 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2659 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2660 void
2662 for(intCrdT x=0; x<numPixX/2; x++)
2663 for(intCrdT y=0; y<numPixY; y++) {
2664 colorT aColor = getPxColor(numPixX-x-1, y);
2665 drawPointNC(numPixX-x-1, y, getPxColor(x, y));
2666 drawPointNC(x, y, aColor);
2667 }
2668 }
2669
2670////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2671 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2672 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2673 void
2675 intCrdT new_numPixX_p = numPixY;
2676 intCrdT new_numPixY_p = numPixX;
2677 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2678 for(intCrdT y=0; y<numPixY; y++)
2679 for(intCrdT x=0; x<numPixX; x++)
2680 new_pixels[new_numPixX_p * (x/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2681 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2682 }
2683
2684////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2685 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2686 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2687 void
2689 intCrdT new_numPixX_p = numPixY;
2690 intCrdT new_numPixY_p = numPixX;
2691 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2692 for(intCrdT y=0; y<numPixY; y++)
2693 for(intCrdT x=0; x<numPixX; x++)
2694 new_pixels[new_numPixX_p * (numPixX-x-1/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2695 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2696 }
2697
2698////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2699 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2700 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2701 void
2703 intCrdT new_numPixX_p = numPixY;
2704 intCrdT new_numPixY_p = numPixX;
2705 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2706 for(intCrdT y=0; y<numPixY; y++)
2707 for(intCrdT x=0; x<numPixX; x++)
2708 new_pixels[new_numPixX_p * (x/*y-crd*/) + (numPixY-y-1/*x-crd*/)] = getPxColor(x, y);
2709 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2710 }
2711
2712////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2713 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2714 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2715 void
2717 intCrdT new_numPixX_p = numPixX;
2718 intCrdT new_numPixY_p = numPixY;
2719 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2720 for(intCrdT y=0; y<numPixY; y++)
2721 for(intCrdT x=0; x<numPixX; x++)
2722 new_pixels[new_numPixX_p * (numPixY-y-1/*y-crd*/) + (numPixX-x-1/*x-crd*/)] = getPxColor(x, y);
2723 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2724 }
2725
2726////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2727 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2728 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2731 unsigned int endiannessProbe = 1;
2732 if(((char *)&endiannessProbe)[0]) {
2733 return endianType::LITTLE;
2734 } else {
2735 return endianType::BIG;
2736 }
2737 }
2738
2739////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2740 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2741 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2742 inline void
2745 int numBytes,
2746 uint64_t data) {
2747 if(numBytes>0) {
2748 if (numBytes == 1) {
2749 uint8_t tmp = (data & 0xff);
2750 oStream.write((const char *)&tmp, 1);
2751 } else {
2752 if (numBytes<9) {
2753 endianType endiannessToUse = (endianness == endianType::AUTO ? platformEndianness() : endianness);
2754 if(endiannessToUse == endianType::LITTLE) {
2755 for(int curByte=0; curByte<numBytes; curByte++) {
2756 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2757 oStream.write((const char *)&tmp, 1);
2758 }
2759 } else {
2760 for(int curByte=(numBytes-1); curByte>=0; curByte--) {
2761 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2762 oStream.write((const char *)&tmp, 1);
2763 }
2764 }
2765 }
2766 }
2767 }
2768 }
2769
2770////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2771 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2772 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2773 void
2775 for(intCrdT yi=0;yi<numPixY;yi++) {
2776 for(intCrdT xi=0;xi<numPixX;xi++) {
2777 fltCrdT xf = int2realX(xi);
2778 fltCrdT yf = int2realY(yi);
2779 colorT aColor = cFun(xf, yf);
2780 drawPoint(xi, yi, aColor);
2781 }
2782 }
2783 }
2784
2785////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2786 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2787 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2788 void
2790 for(intCrdT yi=0;yi<numPixY;yi++) {
2791 for(intCrdT xi=0;xi<numPixX;xi++) {
2792 pointFltType xyPt(int2realX(xi), int2realY(yi));
2793 colorT aColor = cFun(xyPt);
2794 drawPoint(xi, yi, aColor);
2795 }
2796 }
2797 }
2798
2799////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2800 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2801 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2802 void
2804 for(intCrdT yi=0;yi<numPixY;yi++) {
2805 for(intCrdT xi=0;xi<numPixX;xi++) {
2806 colorT aColor = cFun(xi, yi);
2807 drawPoint(xi, yi, aColor);
2808 }
2809 }
2810 }
2811
2812////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2813 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2814 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2815 void
2817 for(intCrdT yi=0;yi<numPixY;yi++) {
2818 for(intCrdT xi=0;xi<numPixX;xi++) {
2819 pointIntType xyPt(xi, yi);
2820 colorT aColor = cFun(xyPt);
2821 drawPoint(xi, yi, aColor);
2822 }
2823 }
2824 }
2825
2826////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2827 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2828 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2829 inline int
2831
2832 std::ofstream outStream;
2833 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2834 if (outStream.is_open())
2835 outStream.imbue(std::locale::classic());
2836 else
2837 return 1;
2838
2839 if(numPixX < 1) // too skinny
2840 return 6;
2841 if(numPixX > 0xffff) // too wide
2842 return 7;
2843 if(numPixY < 1) // too short
2844 return 8;
2845 if(numPixY > 0xffff) // too tall
2846 return 9;
2847
2848 /* Write header */
2849 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // id length
2850 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colourmaptype
2851 writeUIntToStream(outStream, endianType::LITTLE, 1, 2); // datatypecode: 2 == Truecolor RGB 8-bit, 3 == Monochrome
2852 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit colourmaporigin
2853 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // colurmaplength
2854 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colormapdepth
2855 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit x_origin
2856 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit y_origon
2857 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixX); // Width
2858 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixY); // Height
2859 writeUIntToStream(outStream, endianType::LITTLE, 1, 24); // bits per pixel
2860 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // imagedescriptor
2861
2862 /* Write data */
2863 intCrdT x, y;
2864 /* 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
2865 "for(y=(numPixY-1); y>=0; y--)" and "for(y=0; y<numPixY; y++)". */
2866 bool yNat = isIntAxOrientationNaturalY();
2867 bool xNat = isIntAxOrientationNaturalX();
2868 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
2869 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
2870 colorT aColor = getPxColorRefNC(x, y);
2871 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestBlueChan()));
2872 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestGreenChan()));
2873 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestRedChan()));
2874 }
2875 }
2876 return 0;
2877 }
2878
2879////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2880 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2881 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2882 inline int
2887
2888////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2889 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2890 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2891 template <class rcConT>
2892 inline int
2894
2895 std::ofstream outStream;
2896 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2897 if (outStream.is_open())
2898 outStream.imbue(std::locale::classic());
2899 else
2900 return 1;
2901
2902 outStream << "MJRRAW\n"; // 7 7
2903 outStream << std::setw(19) << std::setfill('0') << pxFilter.getNumPixX() << "x"; // 20 27
2904 outStream << std::setw(19) << std::setfill('0') << pxFilter.getNumPixY() << "y"; // 20 47
2905 outStream << std::setw(27) << std::setfill('0') << rcConT::colorType::channelCount << "c"; // 28 75
2906 outStream << std::setw(11) << std::setfill('0') << rcConT::colorType::bitsPerChan << "b"; // 12 87
2907 outStream << (rcConT::colorType::chanIsUnsigned ? "UNS" : "SGN") << "s"; // 4 91
2908 outStream << (rcConT::colorType::chanIsInt ? "INT" : "FLT") << "t"; // 4 95
2909 outStream << (platformEndianness() == endianType::LITTLE ? "LTL" : "BIG") << "i"; // 4 99
2910 outStream << "\n"; // 1 100
2911
2912 intCrdT x, y;
2913 /* 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
2914 "for(y=(pxFilter.getNumPixY()-1); y>=0; y--)" and "for(y=0; y<pxFilter.getNumPixY(); y++)". */
2915 bool yNat = !(pxFilter.isIntAxOrientationNaturalY());
2916 bool xNat = pxFilter.isIntAxOrientationNaturalX();
2917 for((yNat?y=0:y=(pxFilter.getNumPixY()-1)); (yNat?y<pxFilter.getNumPixY():y>=0); (yNat?y++:y--)) {
2918 for((xNat?x=0:x=(pxFilter.getNumPixX()-1)); (xNat?x<pxFilter.getNumPixX():x>=0); (xNat?x++:x--)) {
2919 typename rcConT::colorType aColor = pxFilter.getPxColorNC(x, y);
2920 for(int c=0; c<aColor.channelCount; c++) {
2921 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
2922 outStream.write((const char *)&aChanValue, sizeof(colorChanType));
2923 }
2924 }
2925 }
2926 return 0;
2927 }
2928
2929////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2930 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2931 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2932 inline int
2935 return writeTIFFfile(fileName, tmp, markAlpha);
2936}
2937
2938////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2939 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2940 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2941 template <class rcConT>
2942 inline int
2943 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha) {
2944
2945 if(rcConT::colorType::bitsPerChan < 8) // channels too thin
2946 return 2;
2947 if(rcConT::colorType::bitsPerChan > 0xffff) // channels too fat
2948 return 3;
2949 if(rcConT::colorType::channelCount < 1) // too few channels
2950 return 4;
2951 if(rcConT::colorType::channelCount > 0xffff) // too many channels
2952 return 5;
2953 if(pxFilter.getNumPixX() < 1) // too skinny
2954 return 6;
2955 if(pxFilter.getNumPixX() > 0x7fffffff) // too wide
2956 return 7;
2957 if(pxFilter.getNumPixY() < 1) // too short
2958 return 8;
2959 if(pxFilter.getNumPixY() > 0x7fffffff) // too tall
2960 return 9;
2961 unsigned long bytesPerRow = pxFilter.getNumPixX() * rcConT::colorType::bitsPerChan / 8ul * rcConT::colorType::channelCount;
2962 if(bytesPerRow > 0xffffffff) // rows too big
2963 return 10;
2964 if(bytesPerRow * pxFilter.getNumPixY() > 0xfffffffff) // image too big
2965 return 11;
2966
2967 // //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
2968 const uint16_t tcTIFF_BIGENDIAN = 0x4d4d; /* Magic number for big endian */
2969 const uint16_t tcTIFF_LITTLEENDIAN = 0x4949; /* Magic number for little endian */
2970 const uint16_t tcPHOTOMETRIC_MINISBLACK = 1; /* min value is black */
2971 const uint16_t tcPHOTOMETRIC_RGB = 2; /* RGB color model */
2972 const uint16_t tcORIENTATION_TOPLEFT = 1; /* row 0 top, col 0 lhs */
2973 const uint16_t tcPLANARCONFIG_CONTIG = 1; /* single image plane */
2974 const uint16_t tcRESUNIT_NONE = 1; /* no meaningful units */
2975 const uint16_t tcSAMPLEFORMAT_UINT = 1; /* !unsigned integer data */
2976 const uint16_t tcSAMPLEFORMAT_IEEEFP = 3; /* !IEEE floating point data */
2977
2978 // //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
2979 // const uint16_t tcTIFFTAG_IMAGEWIDTH = 256; /* image width in pixels */
2980 // const uint16_t tcTIFFTAG_IMAGELENGTH = 257; /* image height in pixels */
2981 // const uint16_t tcTIFFTAG_BITSPERSAMPLE = 258; /* bits per channel (sample) */
2982 // const uint16_t tcTIFFTAG_COMPRESSION = 259; /* data compression technique */
2983 // const uint16_t tcTIFFTAG_PHOTOMETRIC = 262; /* photometric interpretation */
2984 // const uint16_t tcTIFFTAG_STRIPOFFSETS = 273; /* offsets to data strips */
2985 // const uint16_t tcTIFFTAG_ORIENTATION = 274; /* +image orientation */
2986 // const uint16_t tcTIFFTAG_SAMPLESPERPIXEL = 277; /* samples per pixel */
2987 // const uint16_t tcTIFFTAG_ROWSPERSTRIP = 278; /* rows per strip of data */
2988 // const uint16_t tcTIFFTAG_STRIPBYTECOUNTS = 279; /* bytes counts for strips */
2989 // const uint16_t tcTIFFTAG_XRESOLUTION = 282; /* pixels/resolution in x */
2990 // const uint16_t tcTIFFTAG_YRESOLUTION = 283; /* pixels/resolution in y */
2991 // const uint16_t tcTIFFTAG_PLANARCONFIG = 284; /* storage organization */
2992 // const uint16_t tcTIFFTAG_RESOLUTIONUNIT = 296; /* units of resolutions */
2993 // const uint16_t tcTIFFTAG_EXTRASAMPLES = 338; /* !info about extra samples */
2994 // const uint16_t tcTIFFTAG_SAMPLEFORMAT = 339; /* !data sample format */
2995
2996 endianType fe = platformEndianness(); // Endian Type
2997 uint16_t endianNum = (fe == endianType::LITTLE ? tcTIFF_LITTLEENDIAN : tcTIFF_BIGENDIAN); // Endianness Magic Number
2998 uint32_t tifWidth = (uint32_t)pxFilter.getNumPixX(); // ImageWidth
2999 uint32_t tifLength = (uint32_t)pxFilter.getNumPixY(); // ImageLength & RowsPerStrip
3000 uint32_t tifSPP = (uint32_t)rcConT::colorType::channelCount; // SamplesPerPixel
3001 uint16_t tifBPS = (uint16_t)(rcConT::colorType::bitsPerChan); // BitsPerSample
3002 uint32_t bytePerSmp = tifBPS / 8; // Bytes per sample
3003 uint32_t tifSBC = tifLength * tifWidth * bytePerSmp * tifSPP; // StripByteCounts
3004 bool haveRGB = tifSPP>=3; // TRUE if this image has RGB data (at least 3 channels)
3005 uint16_t numImgSmp = (haveRGB ? 3 : 1); // Number of samples used for image data (3 for RGB, 1 otherwise)
3006 uint16_t tifPMI = (haveRGB ? tcPHOTOMETRIC_RGB : tcPHOTOMETRIC_MINISBLACK); // PhotometricInterp
3007 uint16_t tifPC = tcPLANARCONFIG_CONTIG; // Planarconfig
3008 uint16_t tifOri = tcORIENTATION_TOPLEFT; // Orientation
3009 uint16_t tifResU = tcRESUNIT_NONE; // Resolution Unit
3010 bool haveXS = !((tifSPP==1) || (tifSPP==3)); // TRUE if this image has ExtraSamples data
3011 bool haveManyXS = tifSPP>4; // TRUE if this image has MORE THAN ONE ExtraSamples data
3012 uint16_t numTags = 1+14 + (haveXS ? 1 : 0); // Number fo tags in this image
3013 bool haveManyBPS = tifSPP>1; // TRUE if this image has MORE THAN ONE BitsPerSample data
3014 uint32_t numXS = tifSPP - numImgSmp; // Number of extra samples
3015 uint32_t xResOff = 14 + 12 * numTags; // XResolution offset
3016 uint32_t yResOff = xResOff + 8; // YResolution offset
3017 uint32_t bpsOff = yResOff + 8; // BitsPerSample offset
3018 uint32_t xsOff = bpsOff + (haveManyBPS ? 2 * tifSPP : 0); // ExtraSamples offset
3019 uint32_t imgOff = xsOff + (haveManyXS ? 2 * numXS : 0); // Image Data offset
3020 uint16_t sampFmt = (rcConT::colorType::chanIsInt ? tcSAMPLEFORMAT_UINT : tcSAMPLEFORMAT_IEEEFP); // SampleFormat (1=unsigned, 3=IEEE)
3021
3022 std::ofstream outStream;
3023 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
3024 if (outStream.is_open())
3025 outStream.imbue(std::locale::classic());
3026 else
3027 return 1;
3028
3029 writeUIntToStream(outStream, fe, 2, endianNum); // Write: little endian magic number
3030 writeUIntToStream(outStream, fe, 2, 42); // Write: TIFF magic number
3031 writeUIntToStream(outStream, fe, 4, 8); // Write: IDF offset
3032 writeUIntToStream(outStream, fe, 2, numTags); // Tag Count
3033 writeUIntToStream(outStream, fe, 2, 0x100); writeUIntToStream(outStream, fe, 2, 4);
3034 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifWidth); // ImageWidth
3035 writeUIntToStream(outStream, fe, 2, 0x101); writeUIntToStream(outStream, fe, 2, 4);
3036 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // ImageLength
3037 writeUIntToStream(outStream, fe, 2, 0x102); writeUIntToStream(outStream, fe, 2, 3);
3038 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifBPS); writeUIntToStream(outStream, fe, 2, 0); // BitsPerSample
3039 writeUIntToStream(outStream, fe, 2, 0x103); writeUIntToStream(outStream, fe, 2, 3);
3040 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, 1); writeUIntToStream(outStream, fe, 2, 0); // Compression
3041 writeUIntToStream(outStream, fe, 2, 0x106); writeUIntToStream(outStream, fe, 2, 3);
3042 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPMI); writeUIntToStream(outStream, fe, 2, 0); // PhotometricIn
3043 writeUIntToStream(outStream, fe, 2, 0x111); writeUIntToStream(outStream, fe, 2, 4);
3044 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, imgOff); // StripOffsets
3045 writeUIntToStream(outStream, fe, 2, 0x112); writeUIntToStream(outStream, fe, 2, 3);
3046 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifOri); writeUIntToStream(outStream, fe, 2, 0); // Orientation
3047 writeUIntToStream(outStream, fe, 2, 0x115); writeUIntToStream(outStream, fe, 2, 3);
3048 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifSPP); writeUIntToStream(outStream, fe, 2, 0); // SamplesPerPixel
3049 writeUIntToStream(outStream, fe, 2, 0x116); writeUIntToStream(outStream, fe, 2, 4);
3050 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // RowsPerStrip
3051 writeUIntToStream(outStream, fe, 2, 0x117); writeUIntToStream(outStream, fe, 2, 4);
3052 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifSBC); // StripByteCounts
3053 writeUIntToStream(outStream, fe, 2, 0x11A); writeUIntToStream(outStream, fe, 2, 5);
3054 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, xResOff); // XResolution
3055 writeUIntToStream(outStream, fe, 2, 0x11B); writeUIntToStream(outStream, fe, 2, 5);
3056 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, yResOff); // YResolution
3057 writeUIntToStream(outStream, fe, 2, 0x11C); writeUIntToStream(outStream, fe, 2, 3);
3058 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPC); writeUIntToStream(outStream, fe, 2, 0); // PlanarConf
3059 writeUIntToStream(outStream, fe, 2, 0x128); writeUIntToStream(outStream, fe, 2, 3);
3060 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifResU); writeUIntToStream(outStream, fe, 2, 0); // ResolutionUnit
3061 if(haveXS) { // ExtraSamples
3062 if(haveManyXS) {
3063 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3064 writeUIntToStream(outStream, fe, 4, numXS); writeUIntToStream(outStream, fe, 4, xsOff);
3065 } else {
3066 if(markAlpha) { // is chan4alpha
3067 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3068 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1);
3069 } else {
3070 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3071 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 0);
3072 }
3073 }
3074 }
3075
3076 writeUIntToStream(outStream, fe, 2, 0x153);
3077 writeUIntToStream(outStream, fe, 2, 3); writeUIntToStream(outStream, fe, 4, 1);
3078 writeUIntToStream(outStream, fe, 2, sampFmt); writeUIntToStream(outStream, fe, 2, 0); // SampleFormat
3079
3080 writeUIntToStream(outStream, fe, 4, 0); // IFD END
3081 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // XResolutionData
3082 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // YResolutionData
3083 if(haveManyBPS) { // YResolutionData
3084 for(unsigned int i=0; i<tifSPP; i++)
3085 writeUIntToStream(outStream, fe, 2, tifBPS);
3086 }
3087 if(haveManyXS) // ExtraSamplesData (can't be RGBA is on xtra, not many)
3088 for(unsigned int i=0; i<numXS; i++)
3089 writeUIntToStream(outStream, fe, 4, 0);
3090 // Image data
3091 intCrdT x, y;
3092 bool yNat = !(pxFilter.isIntAxOrientationNaturalY());
3093 bool xNat = pxFilter.isIntAxOrientationNaturalX();
3094 for((yNat?y=0:y=(pxFilter.getNumPixY()-1)); (yNat?y<pxFilter.getNumPixY():y>=0); (yNat?y++:y--)) {
3095 for((xNat?x=0:x=(pxFilter.getNumPixX()-1)); (xNat?x<pxFilter.getNumPixX():x>=0); (xNat?x++:x--)) {
3096 typename rcConT::colorType aColor = pxFilter.getPxColorNC(x, y);
3097 for(int c=0; c<aColor.channelCount; c++) {
3098 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
3099 if (rcConT::colorType::chanIsInt)
3100 writeUIntToStream(outStream, fe, bytePerSmp, aChanValue); // Sample Data
3101 else
3102 outStream.write((const char *)&aChanValue, bytePerSmp); // Sample Data
3103 }
3104 }
3105 }
3106
3107 return 0;
3108 }
3109
3110////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3111 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3112 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3113 int
3115 intCrdT x1, intCrdT y1,
3116 intCrdT x2, intCrdT y2,
3117 int redChan, int greenChan, int blueChan, int alphaChan) {
3118 if(x1 > x2) // Get x1 < x2
3119 std::swap(x1, x2);
3120 if(y1 > y2) // Get y1 < y2
3121 std::swap(y1, y2);
3122
3123 if(x1 < 0) return 1; // Outside of canvas
3124 if(x2 >= numPixX) return 1; // Outside of canvas
3125 if(y1 < 0) return 1; // Outside of canvas
3126 if(y2 >= numPixY) return 1; // Outside of canvas
3127 if(x2 < x1) return 2; // Region too small (x direction)
3128 if(y2 < y1) return 3; // Region too small (y direction)
3129
3130 int bytesPerPix = (redChan<0?0:1) + (greenChan<0?0:1) + (blueChan<0?0:1) + (alphaChan<0?0:1);
3131 if(bytesPerPix < 1) return 4; // Exit if no channels selected
3132
3133 if(rasterData == 0) // Allocate space if rasterData==NULL. Caller must delete[]
3134 rasterData = (uint8_t *) new uint8_t[(y2-y1+1)*(x2-x1+1)*bytesPerPix];
3135
3136 if(rasterData == 0) return 5; // Exit if something went wrong with allocate...
3137
3138 uint8_t *curPixComp = (uint8_t *)rasterData;
3139 for(intCrdT y=y1; y<=y2; y++) {
3140 for(intCrdT x=x1; x<=x2; x++) {
3141 colorT aColor = getPxColorNC(x, y);
3142 if(redChan >= 0) curPixComp[redChan] = aColor.getChan_byte(aColor.bestRedChan());
3143 if(greenChan >= 0) curPixComp[greenChan] = aColor.getChan_byte(aColor.bestGreenChan());
3144 if(blueChan >= 0) curPixComp[blueChan] = aColor.getChan_byte(aColor.bestBlueChan());
3145 if(alphaChan >= 0) curPixComp[alphaChan] = aColor.getChan_byte(aColor.bestAlphaChan());
3146 curPixComp += bytesPerPix;
3147 } /* end for x */
3148 } /* end for y */
3149
3150 return 0;
3151 }
3152
3153////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3154 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3155 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3156 inline intCrdT
3158 if(realAxOrientationX == realAxisOrientation::NATURAL)
3159 return static_cast<intCrdT>((static_cast<fltCrdT>(x) - minRealX) / pixWidX);
3160 else
3161 return static_cast<intCrdT>((maxRealX - static_cast<fltCrdT>(x)) / pixWidX);
3162 }
3163
3164////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3165 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3166 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3167 inline intCrdT
3169 if(realAxOrientationY == realAxisOrientation::NATURAL)
3170 return static_cast<intCrdT>((static_cast<fltCrdT>(y) - minRealY) / pixWidY);
3171 else
3172 return static_cast<intCrdT>((maxRealY - static_cast<fltCrdT>(y)) / pixWidY);
3173 }
3174
3175////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3176 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3177 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3178 inline fltCrdT
3180 if(realAxOrientationX == realAxisOrientation::NATURAL)
3181 return static_cast<fltCrdT>(x) * pixWidX + minRealX;
3182 else
3183 return maxRealX - static_cast<fltCrdT>(x) * pixWidX;
3184 }
3185
3186////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3187 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3188 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3189 inline fltCrdT
3191 if(realAxOrientationY == realAxisOrientation::NATURAL)
3192 return static_cast<fltCrdT>(y) * pixWidY + minRealY;
3193 else
3194 return maxRealY - static_cast<fltCrdT>(y) * pixWidY;
3195 }
3196
3197////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3198 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3199 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3200 colorT*
3202 colorT *pixelsCopy = new colorT[numPixX * numPixY];
3203 for(intCrdT y=0; y<numPixY; y++)
3204 for(intCrdT x=0; x<numPixX; x++)
3205 pixelsCopy[numPixX * y + x] = getPxColorNC(x, y);
3206 }
3207
3208////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3209 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3210 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3211 inline colorT
3213 if(isOnCanvas(x, y)) [[likely]]
3214 return pixels[numPixX * y + x];
3215 else
3216 return colorT().setToBlack();
3217 }
3218
3219////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3220 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3221 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3222 inline colorT
3224 switch (interpMethod) {
3225 case interpolationType::BILINEAR : return getPxColorInterpBLin(x, y);
3226 case interpolationType::TRUNCATE : return getPxColorInterpBLin(x, y);
3227 case interpolationType::NEAREST : return getPxColorInterpBLin(x, y);
3228 case interpolationType::AVERAGE4 : return getPxColorInterpBLin(x, y);
3229 case interpolationType::AVERAGE9 : return getPxColorInterpBLin(x, y);
3230 default : return colorT("green"); // Just in case I add an enum value, and forget to update this switch.
3231 }
3232 }
3233
3234////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3235 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3236 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3237 colorT
3239 double x1 = std::floor(x);
3240 double y1 = std::floor(y);
3241 double x2 = std::ceil(x);
3242 double y2 = std::ceil(y);
3243
3244 intCrdT x1i = static_cast<intCrdT>(x1);
3245 intCrdT y1i = static_cast<intCrdT>(y1);
3246 intCrdT x2i = static_cast<intCrdT>(x2);
3247 intCrdT y2i = static_cast<intCrdT>(y2);
3248
3249 colorT cF;
3250
3251 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3252 double eps = 0.00001;
3253 double xD21 = x2 - x1;
3254 double yD21 = y2 - y1;
3255 double wH = 1.0;
3256 if (mjr::math::fc::not_near_zero(xD21, eps))
3257 wH = (x - x1) / xD21;
3258 double wV = 1.0;
3259 if (mjr::math::fc::not_near_zero(yD21, eps))
3260 wV = (y - y1) / yD21;
3261
3262 colorT c1;
3263 colorT c2;
3264 c1.linearInterpolate(wH, getPxColorRefNC(x1i, y1i), getPxColorRefNC(x2i, y1i));
3265 c2.linearInterpolate(wH, getPxColorRefNC(x1i, y2i), getPxColorRefNC(x2i, y2i));
3266 cF.linearInterpolate(wV, c1, c2);
3267 } else {
3268 cF.setToBlack();
3269 }
3270 return cF;
3271 }
3272
3273////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3274 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3275 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3276 inline colorT
3278 return getPxColor(static_cast<intCrdT>(std::trunc(x)), static_cast<intCrdT>(std::trunc(y)));
3279 }
3280
3281////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3282 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3283 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3284 inline colorT
3286 return getPxColor(static_cast<intCrdT>(std::round(x)), static_cast<intCrdT>(std::round(y)));
3287 }
3288
3289////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3290 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3291 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3292 inline colorT
3294 intCrdT xi = static_cast<intCrdT>(std::round(x));
3295 intCrdT yi = static_cast<intCrdT>(std::round(y));
3296 colorT newColor;
3297 for(int chan=0; chan<colorT::channelCount; chan++) {
3298 colorChanArithSDPType newChanValue = 0;
3299 for(intCrdT ydi=-1; ydi<=1; ydi++) {
3300 intCrdT icY = yi + ydi;
3301 for(intCrdT xdi=-1; xdi<=1; xdi++) {
3302 intCrdT icX = xi + xdi;
3303 if (!(isCliped(icX, icY))) {
3304 newChanValue += getPxColor(icX, icY).getChan(chan);
3305 }
3306 }
3307 }
3308 newColor.setChan(chan, static_cast<colorChanType>(newChanValue / 9));
3309 }
3310 return newColor;
3311 }
3312
3313////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3314 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3315 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3316 colorT
3318 double x1 = std::floor(x);
3319 double y1 = std::floor(y);
3320 double x2 = std::ceil(x);
3321 double y2 = std::ceil(y);
3322
3323 intCrdT x1i = static_cast<intCrdT>(x1);
3324 intCrdT y1i = static_cast<intCrdT>(y1);
3325 intCrdT x2i = static_cast<intCrdT>(x2);
3326 intCrdT y2i = static_cast<intCrdT>(y2);
3327
3328 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3329
3330 colorT c1 = pixels[numPixX * y1i + x1i];
3331 c1.tfrmMean(pixels[numPixX * y1i + x2i]);
3332
3333 colorT c2 = pixels[numPixX * y2i + x1i];
3334 c2.tfrmMean(pixels[numPixX * y2i + x2i]);
3335
3336 c1.tfrmMean(c2);
3337
3338 return c1;
3339 } else {
3340 return colorT().setToBlack();
3341 }
3342 }
3343
3344// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3345// template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3346// requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3347// void
3348// ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts) {
3349// moveTo(x2, y2); // Do this first
3350// intCrdT x, y;
3351// if(y1 == y2) { // slope = 0
3352// if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
3353// return;
3354// if(x1 > x2) // . Fix point ordering
3355// std::swap(x1, x2);
3356// if(x1 < 0) // . Clip left
3357// x1 = 0;
3358// if(x2 >= numPixX) // . Clip right
3359// x2 = numPixX - 1;
3360// //drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
3361// return; // mark edge
3362// } else if(x1 == x2) { // slope = infinity
3363// if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
3364// return;
3365// if(y1 > y2) // . Fix point ordering
3366// std::swap(y1, y2);
3367// if(y1 < 0) // . Clip top
3368// y1 = 0;
3369// if(y2 >= numPixY) // . Clip bottom
3370// y2 = numPixY - 1;
3371// //drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
3372// for(y=y1; y<=y2; y++) pts[y] = x1; // mark edge
3373// } else { // Slope is not infinity or 0...
3374// int dx, dy;
3375// if(x1 > x2) { // . Fix point ordering
3376// std::swap(x1, x2);
3377// std::swap(y1, y2);
3378// }
3379// dx = x2 - x1; // . Compute the slope
3380// dy = y2 - y1;
3381// if(dx == dy) { // . Slope = 1
3382// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
3383// return;
3384// if(x1 < 0) { // .. Clip left
3385// y1 = y1 - x1;
3386// x1 = 0;
3387// }
3388// if(y1 < 0) { // .. Clip top
3389// x1 = x1 - y1;
3390// y1 = 0;
3391// }
3392// if(x2 >= numPixX) { // .. Clip right
3393// y2 = y2 - (x2 - numPixX) - 1;
3394// x2 = numPixX - 1;
3395// }
3396// if(y2 >= numPixY) { // .. Clip bottom
3397// x2 = x2 - (y2 - numPixY) - 1;
3398// y2 = numPixY - 1;
3399// }
3400// for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
3401// //drawPointNC(x, y, color);
3402// pts[y] = x; // mark edge
3403// } else if(dx == -dy) { // . Slope = -1
3404// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
3405// return;
3406// if(x1 < 0) { // .. Clip left
3407// y1 = y1 + x1;
3408// x1 = 0;
3409// }
3410// if(x2 >= numPixX) { // .. Clip right
3411// y2 = y2 + (x2 - (numPixX - 1));
3412// x2 = numPixX - 1;
3413// }
3414// if(y2 < 0) { // .. Clip top
3415// x2 = x2 + y2;
3416// y2 = 0;
3417// }
3418// if(y1 >= numPixY) { // .. Clip bottom
3419// x1 = x1 + (y1 - (numPixY - 1));
3420// y1 = numPixY - 1;
3421// }
3422// for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
3423// //drawPointNC(x, y, color);
3424// pts[y] = x; // mark edge
3425// } else { // . Slope != 1, -1, 0, \infinity
3426// int s, dx2, dy2;
3427// dx2 = 2*dx;
3428// dy2 = 2*dy;
3429// if(dy > 0) { // .. Positive Slope
3430// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
3431// return;
3432// if(x1 < 0) { // ... Clip left
3433// y1 = (int)(1.0*y1-x1*dy/dx);
3434// x1 = 0;
3435// }
3436// if(y1 < 0) { // ... Clip top
3437// x1 = (int)(1.0*x1-y1*dx/dy);
3438// y1 = 0;
3439// }
3440// if(x2 >= numPixX) { // ... Clip right
3441// y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
3442// x2 = numPixX - 1;
3443// }
3444// if(y2 >= numPixY) { // ... Clip bottom
3445// x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
3446// y2 = numPixY - 1;
3447// }
3448// if(dx > dy) { // ... 0 < Slope < 1
3449// s = dy2 - dx;
3450// x=x1;
3451// y=y1;
3452// while(x<=x2) { // .... Draw Line
3453// //drawPoint(x, y, color);
3454// pts[y] = x; // mark edge
3455// if(s < 0) {
3456// s += dy2;
3457// } else {
3458// y++;
3459// s += dy2 - dx2;
3460// }
3461// x++;
3462// }
3463// } else { // ... 1 < Slope < infinity
3464// s = dy - dx2;
3465// x=x1;
3466// y=y1;
3467// while(y<=y2) { // .... Draw Line
3468// //drawPoint(x, y, color);
3469// pts[y] = x; // mark edge
3470// if(s > 0) {
3471// s -= dx2;
3472// } else {
3473// x++;
3474// s += dy2 - dx2;
3475// }
3476// y++;
3477// }
3478// }
3479// } else { // .. Negative Slope
3480// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
3481// return;
3482// if(x1 < 0) { // ... Clip left
3483// y1 = (int)(1.0*y1-x1*dy/dx);
3484// x1 = 0;
3485// }
3486// if(y2 < 0) { // ... Clip top
3487// x2 = (int)(1.0*x2-y2*dx/dy);
3488// y2 = 0;
3489// }
3490// if(x2 >= numPixX) { // ... Clip right
3491// y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
3492// x2 = numPixX - 1;
3493// }
3494// if(y1 >= numPixY) { // ... Clip bottom
3495// x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
3496// y1 = numPixY - 1;
3497// }
3498// if(dx > -dy) { // ... 0 > Slope > -infinity
3499// s = dy2 + dx;
3500// x=x1;
3501// y=y1;
3502// while(x<=x2) { // .... Draw Line
3503// //drawPoint(x, y, color);
3504// pts[y] = x; // mark edge
3505// if(s > 0) {
3506// s += dy2;
3507// } else {
3508// y--;
3509// s += dy2 + dx2;
3510// }
3511// x++;
3512// }
3513// } else { // ... -1 > Slope > -inf
3514// s = dy + dx2;
3515// x=x1;
3516// y=y1;
3517// while(y>=y2) { // .... Draw Line
3518// //drawPoint(x, y, color);
3519// pts[y] = x; // mark edge
3520// if(s < 0) {
3521// s += dx2;
3522// } else {
3523// x++;
3524// s += dy2 + dx2;
3525// }
3526// y--;
3527// }
3528// }
3529// }
3530// }
3531// }
3532// }
3533
3534////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3535 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3536 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3537 inline void
3538 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin) {
3539 // This code is essentially the line drawing code with some simplifications.
3540 intCrdT x, y;
3541 if(x1 == x2) { // slope = infinity
3542 if(y1 > y2) // Fix point ordering
3543 std::swap(y1, y2);
3544 for(y=y1; y<=y2; y++) // Draw PIxels: drawVertLineNC(y1, y2, x1, color);
3545 pts[y]=x1; // set bound
3546 } else { // Slope is not infinity or 0...
3547 int dx, dy;
3548 if(x1 > x2) { // Fix point ordering
3549 std::swap(x1, x2);
3550 std::swap(y1, y2);
3551 }
3552 dx = x2 - x1; // Compute the slope
3553 dy = y2 - y1;
3554 if(dx == dy) { // Slope = 1
3555 for(x=x1,y=y1;x<=x2;y++,x++) // Draw Pixels
3556 pts[y]=x; // set bound
3557 } else if(dx == -dy) { // Slope = -1
3558 for(x=x1,y=y1;x<=x2;y--,x++) // Draw Pixels
3559 pts[y]=x; // set bound
3560 } else { // Slope != 1, -1, 0, \infinity
3561 int s, dx2, dy2;
3562 dx2 = 2*dx;
3563 dy2 = 2*dy;
3564 if(dy > 0) { // Positive Slope
3565 if(dx > dy) { // 0 < Slope < 1
3566 if (findMin) {
3567 s = dy2 - dx;
3568 x=x1;
3569 y=y1;
3570 intCrdT lastY=y-1;
3571 while(x<=x2) { // Draw Line
3572 if (y != lastY)
3573 pts[y]=x; // set bound
3574 lastY = y;
3575 if(s < 0) {
3576 s += dy2;
3577 } else {
3578 y++;
3579 s += dy2 - dx2;
3580 }
3581 x++;
3582 }
3583 } else { // works.
3584 s = dy2 - dx;
3585 x=x1;
3586 y=y1;
3587 while(x<=x2) { // Draw Line
3588 pts[y]=x; // set bound
3589 if(s < 0) {
3590 s += dy2;
3591 } else {
3592 y++;
3593 s += dy2 - dx2;
3594 }
3595 x++;
3596 }
3597 }
3598 } else { // 1 < Slope < infinity
3599 s = dy - dx2;
3600 x=x1;
3601 y=y1;
3602 while(y<=y2) { // Draw Line
3603 pts[y]=x; // set bound
3604 if(s > 0) {
3605 s -= dx2;
3606 } else {
3607 x++;
3608 s += dy2 - dx2;
3609 }
3610 y++;
3611 }
3612 }
3613 } else { // Negative Slope
3614 if(dx > -dy) { // 0 > Slope > -1
3615 if (findMin) {
3616 s = dy2 + dx;
3617 x=x1;
3618 y=y1;
3619 intCrdT lastY=y-1;
3620 while(x<=x2) { // Draw Line
3621 if (y != lastY)
3622 pts[y]=x; // set bound
3623 lastY = y;
3624 if(s > 0) {
3625 s += dy2;
3626 } else {
3627 y--;
3628 s += dy2 + dx2;
3629 }
3630 x++;
3631 }
3632 } else {
3633 s = dy2 + dx;
3634 x=x1;
3635 y=y1;
3636 while(x<=x2) { // Draw Line
3637 pts[y]=x; // set bound
3638 if(s > 0) {
3639 s += dy2;
3640 } else {
3641 y--;
3642 s += dy2 + dx2;
3643 }
3644 x++;
3645 }
3646 }
3647 } else { // -1 > Slope > -inf
3648 s = dy + dx2;
3649 x=x1;
3650 y=y1;
3651 while(y>=y2) { // Draw Line
3652 pts[y]=x; // set bound
3653 if(s < 0) {
3654 s += dx2;
3655 } else {
3656 x++;
3657 s += dy2 + dx2;
3658 }
3659 y--;
3660 }
3661 }
3662 }
3663 }
3664 }
3665 }
3666
3667////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3668 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3669 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3670 inline void
3671 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3672 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color, color, color, true);
3673 }
3674
3675////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3676 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3677 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3678 inline void
3680 intCrdT x2, intCrdT y2,
3681 intCrdT x3, intCrdT y3,
3682 colorArgType color1, colorArgType color2, colorArgType color3) {
3683 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color1, color2, color3, false);
3684 }
3685
3686////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3687 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3688 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3689 void
3691 intCrdT x2, intCrdT y2,
3692 intCrdT x3, intCrdT y3,
3693 colorT c1, colorT c2, colorT c3, bool solid) { // Not colorArgType because of std::swap
3694 static intCrdT *minPts, *maxPts;
3695 static intCrdT numPts;
3696
3697 if( isCliped(x1, y1) || isCliped(x2, y2) || isCliped(x3, y3))
3698 return;
3699
3700 ///////////////////////////////////////////////////////////////////////////////////
3701 // Check our work space, and allocate/reallocate as required.
3702 if(minPts == NULL) { // First time in function -- allocate
3703 minPts = new intCrdT[numPixY];
3704 maxPts = new intCrdT[numPixY];
3705 numPts = numPixY;
3706 } else { // Not our first time! We have a work space.
3707 if(numPts != numPixY) { // Work space is wrong size -- reallocate
3708 delete[] minPts;
3709 delete[] maxPts;
3710 minPts = new intCrdT[numPixY];
3711 maxPts = new intCrdT[numPixY];
3712 numPts = numPixY;
3713 }
3714 }
3715
3716 ///////////////////////////////////////////////////////////////////////////////////
3717 if (!(solid) && ((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) == 0))
3718 return;
3719
3720 ///////////////////////////////////////////////////////////////////////////////////
3721 // Sort (x1,y1), (x2,y2), (x3,y3) so that y1 >= y2, y3 and y3 <= y2, y1
3722 if(y1 > y2) { // top != 2 && bot != 1
3723 if(y1 > y3) { // top != 3 y1>y2 y1>y3 y2>y3 top bot
3724 if(y2 > y3) { // bot != 2 . . . . .
3725 // T T T 1 3 NOP
3726 } else { // bot != 3 . . . . .
3727 std::swap(y2,y3); // T T F 1 2 SWAP(2,3)
3728 std::swap(x2,x3); // . . . . .
3729 std::swap(c2,c3); // . . . . .
3730 } // . . . . .
3731 } else { // top != 1 . . . . .
3732 std::swap(y1,y3); // T F U 3 2 SWAP(1,3) SWAP(2,3)
3733 std::swap(y2,y3); // . . . . .
3734 std::swap(x1,x3); // . . . . .
3735 std::swap(x2,x3); // . . . . .
3736 if(!solid) { // . . . . .
3737 std::swap(c1,c3); // . . . . .
3738 std::swap(c2,c3); // . . . . .
3739 } // . . . . .
3740 } // . . . . .
3741 } else { // top != 1 . . . . .
3742 if(y2 > y3) { // top != 3 && bot != 2 . . . . .
3743 if(y1 > y3) { // bot != 1 . . . . .
3744 std::swap(y1,y2); // F T T 2 3 SWAP(1,2)
3745 std::swap(x1,x2); // . . . . .
3746 std::swap(c1,c2); // . . . . .
3747 } else { // bot != 3 . . . . .
3748 std::swap(y1,y2); // F F T 2 1 SWAP(1,2) SWAP(2,3)
3749 std::swap(y2,y3); // . . . . .
3750 std::swap(x1,x2); // . . . . .
3751 std::swap(x2,x3); // . . . . .
3752 if(!solid) { // . . . . .
3753 std::swap(c1,c2); // . . . . .
3754 std::swap(c2,c3); // . . . . .
3755 } // . . . . .
3756 } // . . . . .
3757 } else { // top != 2 && bot != 3 . . . . .
3758 std::swap(y1,y3); // F U F 3 1 SWAP(1,3)
3759 std::swap(x1,x3); // . . . . .
3760 std::swap(c1,c3); // . . . . .
3761 }
3762 }
3763
3764 ///////////////////////////////////////////////////////////////////////////////////////
3765 /* cA y1==y2 point 1,2,3 */
3766 /* cB-cG y1==y2 h line 1,2---3 3---1,2 1,3---2 2---1,3 2,3---1 1---2,3 */
3767 /* cH-cJ y1==y2 v line 1,2 1,2 1,2 */
3768 /* \ | / */
3769 /* 3 3 3 */
3770 /* cK-cL y1==y2 tri 1---2 2---1 */
3771 /* \ / \ / */
3772 /* 3 3 */
3773 /* cM-cO y2=y3 v line 1 1 1 */
3774 /* \ | / */
3775 /* 2,3 2,3 2,3 */
3776 /* cP-cQ y2=y3 tri 1 1 */
3777 /* / \ / \ */
3778 /* 2---3 3---2 */
3779 /* cR-cS General 1 1 Note x1 need not equal x3 in these cases! */
3780 /* |\ /| It is just difficult to draw a case with */
3781 /* | 2 2 | x1 != x3 with tiny ASCII art... */
3782 /* |/ \| */
3783 /* 3 3 */
3784 ///////////////////////////////////////////////////////////////////////////////////////
3785
3786 if(y1==y3) { // cA-cG
3787 minPts[y1] = mjr::math::odr::min3(x1, x2, x3); //
3788 maxPts[y1] = mjr::math::odr::max3(x1, x2, x3); //
3789 } else { // cH-cS
3790 if(y1==y2) { // cH-cL
3791 if(x1==x2) { // cH-cJ
3792 triangleEdger(x1, y1, x3, y3, minPts, true); //
3793 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3794 } else if(x1<x2) { // cK
3795 triangleEdger(x1, y1, x3, y3, minPts, true); //
3796 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3797 } else { // cJ
3798 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3799 triangleEdger(x2, y2, x3, y3, minPts, true); //
3800 } //
3801 } else if(y2==y3) { // cM-cQ
3802 if(x2==x3) { // cM-cO
3803 triangleEdger(x1, y1, x3, y3, minPts, true); //
3804 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3805 } else if(x2<x3) { // cP
3806 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3807 triangleEdger(x2, y2, x1, y1, minPts, true); //
3808 } else { // cQ
3809 triangleEdger(x1, y1, x3, y3, minPts, true); //
3810 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3811 } //
3812 } else { // cR-cS
3813 double xOt = (x1*y3+x3*y2-x1*y2-x3*y1); //
3814 double xOb = (y3-y1); //
3815 if(xOt/xOb < x2) { // cR
3816 triangleEdger(x1, y1, x3, y3, minPts, true); //
3817 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3818 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3819 } else { // cS
3820 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3821 triangleEdger(x2, y2, x1, y1, minPts, true); //
3822 triangleEdger(x2, y2, x3, y3, minPts, true); //
3823 } //
3824 } //
3825 } //
3826
3827 ///////////////////////////////////////////////////////////////////////////////////
3828 // Fill between the left and right bits.
3829 if(solid) {
3830 for(intCrdT y=y3; y<=y1; y++)
3831 drawLine(minPts[y], y, maxPts[y], y, c1);
3832 } else {
3833 for(intCrdT y=y3; y<=y1; y++)
3834 for(intCrdT x=minPts[y]; x<=maxPts[y]; x++) {
3835 /* Performance & Correctness: This code seems very poorly optimized. Especially the computation of w3 instead of simply using 1-w1-w2, and the
3836 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
3837 computations. Sometimes, for example, the coordinates of a fill point won't, technically, be in the triangle. Or the sum of the areas
3838 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
3839 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
3840 consistency and accuracy on edges. The repeated common expressions are optimized by the compiler. This branch is roughly 15x slower than the
3841 solid branch above. */
3842 colorChanArithFltType w1 = std::abs(static_cast<colorChanArithFltType>( x*(y2 - y3) + x2*(y3 - y) + x3*(y - y2)));
3843 colorChanArithFltType w2 = std::abs(static_cast<colorChanArithFltType>(x1*(y - y3) + x*(y3 - y1) + x3*(y1 - y)));
3844 colorChanArithFltType w3 = std::abs(static_cast<colorChanArithFltType>(x1*(y2 - y) + x2*(y - y1) + x*(y1 - y2)));
3845 drawPointNC(x, y, colorT().wMean(w1/(w1+w2+w3), w2/(w1+w2+w3), w3/(w1+w2+w3), c1, c2, c3));
3846 }
3847 }
3848 }
3849
3850////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3851 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3852 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3853 inline void
3855 drawPLCurve(numPoints, x, y, dfltColor);
3856 }
3857
3858////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3859 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3860 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3861 inline void
3863 for(int i=0; i<numPoints-1; i++)
3864 drawLine(real2intX(x[i]), real2intY(y[i]), real2intX(x[i+1]), real2intY(y[i+1]), color);
3865 }
3866
3867////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3868 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3869 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3870 inline void
3872 drawPLCurve(numPoints, x, y, dfltColor);
3873 }
3874
3875////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3876 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3877 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3878 inline void
3880 for(int i=0; i<numPoints-1; i++)
3881 drawLine(x[i], y[i], x[i+1], y[i+1], color);
3882 }
3883
3884////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3885 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3886 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3887 inline void
3889 for(int i=0; i<numPoints-1; i++)
3890 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3891 }
3892
3893////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3894 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3895 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3896 inline void
3898 for(int i=0; i<numPoints-1; i++)
3899 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3900 }
3901
3902////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3903 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3904 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3905 inline void
3907 drawPLCurve(numPoints, thePoints, dfltColor);
3908 }
3909
3910////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3911 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3912 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3913 inline void
3915 drawPLCurve(numPoints, thePoints, dfltColor);
3916 }
3917
3918////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3919 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3920 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3921 inline void
3922 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3923 drawLine(x1, y1, x2, y2, color);
3924 drawLine(x2, y2, x3, y3, color);
3925 drawLine(x3, y3, x1, y1, color);
3926 }
3927
3928////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3929 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3930 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3931 void
3932 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
3933 int x = 0;
3934 int y = radiusX;
3935 int d = 1 - radiusX;
3936 int deltaE = 3;
3937 int deltaSE = -2 * radiusX + 5;
3938
3939 drawPoint( x+centerX, y+centerY, color);
3940 drawPoint( x+centerX,-y+centerY, color);
3941 drawPoint(-x+centerX, y+centerY, color);
3942 drawPoint(-x+centerX,-y+centerY, color);
3943 drawPoint( y+centerX, x+centerY, color);
3944 drawPoint( y+centerX,-x+centerY, color);
3945 drawPoint(-y+centerX, x+centerY, color);
3946 drawPoint(-y+centerX,-x+centerY, color);
3947
3948 while(y>x) {
3949 if(d<0) {
3950 d += deltaE;
3951 deltaE += 2;
3952 deltaSE += 2;
3953 } else {
3954 d += deltaSE;
3955 deltaE += 2;
3956 deltaSE += 4;
3957 y--;
3958 }
3959 x++;
3960 drawPoint( x+centerX, y+centerY, color);
3961 drawPoint( x+centerX,-y+centerY, color);
3962 drawPoint(-x+centerX, y+centerY, color);
3963 drawPoint(-x+centerX,-y+centerY, color);
3964 drawPoint( y+centerX, x+centerY, color);
3965 drawPoint( y+centerX,-x+centerY, color);
3966 drawPoint(-y+centerX, x+centerY, color);
3967 drawPoint(-y+centerX,-x+centerY, color);
3968 }
3969
3970 }
3971
3972////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3973 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3974 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3975 void
3976 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
3977 int minXY;
3978 int x = 0;
3979 int y = radiusX;
3980 int d = 1 - radiusX;
3981 int deltaE = 3;
3982 int deltaSE = -2 * radiusX + 5;
3983
3984 if(x > y)
3985 minXY = y;
3986 else
3987 minXY = x;
3988 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
3989 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
3990 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
3991 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
3992 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
3993 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
3994 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
3995 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
3996
3997 while(y>x) {
3998 if(d<0) {
3999 d += deltaE;
4000 deltaE += 2;
4001 deltaSE += 2;
4002 } else {
4003 d += deltaSE;
4004 deltaE += 2;
4005 deltaSE += 4;
4006 y--;
4007 }
4008 x++;
4009
4010 if(x > y)
4011 minXY = y;
4012 else
4013 minXY = x;
4014 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
4015 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
4016 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
4017 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
4018 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
4019 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
4020 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4021 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4022 }
4023 }
4024
4025////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4026 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4027 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4028 void
4029 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
4030 if(x1 > x2) // Get x1 < x2
4031 std::swap(x1, x2);
4032 if(y1 > y2) // Get y1 < y2
4033 std::swap(y1, y2);
4034 if( (y1 < numPixY) && (x1 < numPixX) && (y2 >= 0) && (x2 >= 0) ) { // Part of rect visible
4035 int noTop, noBottom, noLeft, noRight;
4036 if((noTop=(y1 < 0)))
4037 y1 = 0;
4038 if((noLeft=(x1 < 0)))
4039 x1 = 0;
4040 if((noBottom=(y2 >= numPixY)))
4041 y2 = numPixY - 1;
4042 if((noRight=(x2 >= numPixX)))
4043 x2 = numPixX - 1;
4044 // Draw top/bottom/left/right lines
4045 if(!noLeft) // Have left
4046 drawVertLineNC(y1, y2, x1, color);
4047 if(!noRight) // Have Right
4048 drawVertLineNC(y1, y2, x2, color);
4049 if(!noTop) // Have top
4050 drawHorzLineNC(x1, x2, y1, color);
4051 if(!noBottom) // Have bottom
4052 drawHorzLineNC(x1, x2, y2, color);
4053 }
4054 }
4055
4056////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4057 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4058 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4059 inline void
4061 if(x1 > x2) // Get x1 < x2
4062 std::swap(x1, x2);
4063 if(y1 > y2) // Get y1 < y2
4064 std::swap(y1, y2);
4065 // Clip
4066 if( (y1 >= numPixY) || (x1 >= numPixX) || (y2 < 0) || (x2 < 0) )
4067 return;
4068 if(y1 < 0)
4069 y1 = 0;
4070 if(x1 < 0)
4071 x1 = 0;
4072 if(y2 >= numPixY)
4073 y2 = numPixY - 1;
4074 if(x2 >= numPixX)
4075 x2 = numPixX - 1;
4076 for(intCrdT y=y1;y<=y2;y++)
4077 drawHorzLineNC(x1, x2, y, color);
4078 }
4079
4080////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4081 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4082 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4083 inline void
4085 if constexpr (enableDrawModes)
4086 switch(drawMode) {
4087 case drawModeType::SET: getPxColorRefNC(x, y).copy(color); break;
4088 case drawModeType::XOR: getPxColorRefNC(x, y).tfrmXor(color); break;
4089 case drawModeType::ADDCLAMP: getPxColorRefNC(x, y).tfrmAddClamp(color); break;
4090 case drawModeType::AND: getPxColorRefNC(x, y).tfrmAnd(color); break;
4091 case drawModeType::OR: getPxColorRefNC(x, y).tfrmOr(color); break;
4092 case drawModeType::DIFFCLAMP: getPxColorRefNC(x, y).tfrmDiffClamp(color); break;
4093 case drawModeType::MULTCLAMP: getPxColorRefNC(x, y).tfrmMultClamp(color); break;
4094 }
4095 else
4096 getPxColorRefNC(x, y).copy(color);
4097 }
4098
4099////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4100 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4101 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4102 void
4104 if (xfactor > 1) {
4105 intCrdT new_numPixX_p = xfactor*numPixX;
4106 intCrdT new_numPixY_p = xfactor*numPixY;
4107 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4108 for(intCrdT y=0, y1=0; y<numPixY; y++) {
4109 for(intCrdT x=0, x1=0; x<numPixX; x++) {
4110 for(int i=0; i<xfactor; i++) {
4111 for(int j=0; j<xfactor; j++) {
4112 new_pixels[new_numPixX_p * y1 + x1] = getPxColor(x, y);
4113 x1++;
4114 }
4115 x1-=xfactor;
4116 y1++;
4117 }
4118 x1+=xfactor;
4119 y1-=xfactor;
4120 }
4121 y1+=xfactor;
4122 }
4123 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4124 }
4125 }
4126
4127////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4128 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4129 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4130 void
4132 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4133 intCrdT new_numPixX_p = numPixX/xfactor;
4134 intCrdT new_numPixY_p = numPixY/xfactor;
4135 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4136 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4137 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor)
4138 new_pixels[new_numPixX_p * y + x] = getPxColor(x1, y1);
4139 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4140 }
4141 }
4142
4143////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4144 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4145 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4146 void
4148 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4149 intCrdT new_numPixX_p = numPixX/xfactor;
4150 intCrdT new_numPixY_p = numPixY/xfactor;
4151 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4152 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4153 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4154 std::vector<colorChanArithSDPType> sums(colorT::channelCount, static_cast<colorChanArithSDPType>(0));
4155 for(int j=0; j<xfactor; j++)
4156 for(int i=0; i<xfactor; i++)
4157 for(int c=0; c<colorT::channelCount; c++)
4158 sums[c] += getPxColor(x1+i, y1+j).getChan(c);
4159 colorT aColor;
4160 for(int c=0; c<colorT::channelCount; c++)
4161 aColor.setChan(c, static_cast<colorChanType>(sums[c] / (xfactor*xfactor)));
4162 new_pixels[new_numPixX_p * y + x] = aColor;
4163 }
4164 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4165 }
4166 }
4167
4168////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4169 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4170 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4171 void
4173 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4174 intCrdT new_numPixX_p = numPixX/xfactor;
4175 intCrdT new_numPixY_p = numPixY/xfactor;
4176 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4177 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4178 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4179 colorT maxColor = getPxColor(xfactor*x, xfactor*y);
4180 for(int yi=0; yi<xfactor; yi++)
4181 for(int xi=0; xi<xfactor; xi++)
4182 maxColor.tfrmMaxI(getPxColor(xfactor*x+xi, xfactor*y+yi));
4183 new_pixels[new_numPixX_p * y + x] = maxColor;
4184 }
4185 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4186 }
4187 }
4188
4189////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4190 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4191 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4192 void
4194 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4195 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4196 kernel[kSize * yi + xi] = exp(-(xis*xis+yis*yis)/(2*sd*sd))/(sd*sd*2*std::numbers::pi);
4197 double divisor = 0;
4198 for(int i=0; i<(kSize*kSize); i++)
4199 divisor += kernel[i];
4200 for(int i=0; i<(kSize*kSize); i++)
4201 kernel[i] /= divisor;
4202 }
4203
4204////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4205 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4206 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4207 void
4209 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4210 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4211 kernel[kSize * yi + xi] = 1.0/(kSize*kSize);
4212 }
4213
4214////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4215 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4216 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4217 void
4218 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::convolution(double *kernel, int kWide, int kTall, double divisor) {
4219 colorT *new_pixels = new colorT[numPixX * numPixY];
4220 // Divisor is invalid, so we compute one to use
4221 if (mjr::math::fc::near_zero(divisor, 0.0001)) {
4222 divisor = 0.0;
4223 for(int i=0; i<(kWide*kTall); i++)
4224 divisor += kernel[i];
4225 }
4226 // Apply filter
4227 double tmp[colorT::channelCount];
4228 for(intCrdT y=0; y<numPixY; y++) {
4229 for(intCrdT x=0; x<numPixX; x++) {
4230 colorT newColor;
4231 for(int chan=0; chan<colorT::channelCount; chan++)
4232 tmp[chan] = 0.0;
4233 for(int yi=0, yis=-(kTall/2); yi<kTall; yi++, yis++) {
4234 intCrdT icY = y + yis;
4235 for(int xi=0,xis=-(kWide/2); xi<kWide; xi++, xis++) {
4236 intCrdT icX = x + xis;
4237 if (!(isCliped(icX, icY))) {
4238 for(int chan=0; chan<colorT::channelCount; chan++)
4239 tmp[chan] += static_cast<double>(getPxColor(icX, icY).getChan(chan)) * kernel[kWide * yi + xi];
4240 }
4241 }
4242 }
4243 for(int chan=0; chan<colorT::channelCount; chan++)
4244 new_pixels[numPixX * y + x].setChan(chan, static_cast<colorChanType>(tmp[chan] / divisor));
4245 }
4246 }
4247 rePointPixels(new_pixels, numPixX, numPixY);
4248 }
4249
4250////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4251 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4252 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4253 inline void
4255 convolution(kernel, kSize, kSize, divisor);
4256 }
4257////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4258 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4259 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4260 inline void
4262 convolution(kernel, kSize, kSize, 1.0);
4263 }
4264
4265////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4266 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4267 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4268 void
4269 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor) {
4270 intCrdT x1, y1;
4271 int actionIsMoveTo;
4272
4273 if( (glyphNum < 0) || (glyphNum > 3934) )
4274 glyphNum = 699;
4275
4276 actionIsMoveTo=1;
4277 for(int i=0; i<(mjr::hershey::chars[glyphNum]).numComp; i++) {
4278 if((mjr::hershey::chars[glyphNum]).components[2*i] == ' ') {
4279 actionIsMoveTo = 1;
4280 } else {
4281 if(isIntAxOrientationNaturalX())
4282 x1 = static_cast<intCrdT>(magX * ((mjr::hershey::chars[glyphNum]).components[2*i] - 'R'));
4283 else
4284 x1 = static_cast<intCrdT>(magX * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i]));
4285
4286 if(isIntAxOrientationNaturalY())
4287 y1 = static_cast<intCrdT>(magY * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i+1]));
4288 else
4289 y1 = static_cast<intCrdT>(magY * ((mjr::hershey::chars[glyphNum]).components[2*i+1] - 'R'));
4290
4291 if(actionIsMoveTo) {
4292 moveTo(x1+x, y1+y);
4293 actionIsMoveTo = 0;
4294 } else {
4295 drawLine(x1+x, y1+y, aColor);
4296 }
4297 }
4298 }
4299 }
4300
4301////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4302 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4303 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4304 inline void
4305 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc) {
4306 for(auto &c : aString) {
4307 int glyphNum = 0;
4308 if((c>=32) && (c<=126))
4309 glyphNum = mjr::hershey::ascii2hershey[(int)aFont][c-32];
4310 drawHersheyGlyph(glyphNum, x, y, cex, cex, aColor);
4311 x+=static_cast<intCrdT>(spc*cex);
4312 }
4313 }
4314
4315////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4316 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4317 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4318 inline void
4320 mjr::hershey::font aFont,
4321 intCrdT x, intCrdT y,
4322 colorArgType stringColor, colorArgType boxColor,
4323 double cex, intCrdT spc) {
4324 drawFillRectangle(static_cast<intCrdT>(x-spc*cex),
4325 static_cast<intCrdT>(y-spc*cex),
4326 static_cast<intCrdT>(x+spc*cex*static_cast<int>(aString.length())),
4327 static_cast<intCrdT>(y+spc*cex),
4328 boxColor);
4329 drawString(aString, aFont, x, y, stringColor, cex, spc);
4330 }
4331
4332////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4333 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4334 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4335 int
4337 char strBuf[256];
4338
4339 std::ifstream iStream(fileName, std::ios_base::binary);
4340
4341 if (!(iStream.good()))
4342 return 1;
4343
4344 iStream.getline(strBuf, 10, '\n');
4345 if (!(iStream.good()))
4346 return 11;
4347 if (iStream.gcount() != 7)
4348 return 24;
4349 if(std::string(strBuf) != std::string("MJRRAW"))
4350 return 24;
4351
4352 int fileWide = -1;
4353 int fileTall = -1;
4354 int fileChans = -1;
4355 int fileBitPerChan = -1;
4356 bool fileIsSGN = true, fileHasS = false;
4357 bool fileIsInt = true, fileHasT = false;
4358 bool fileIsLTL = true, fileHasI = false;
4359
4360 iStream.getline(strBuf, 100, '\n');
4361 if (!(iStream.good()))
4362 return 11;
4363 if (iStream.gcount() != 93)
4364 return 26;
4365
4366 std::string::size_type tagIdx;
4367 std::string::size_type prcIdx = 0;
4368 std::string strBufS(strBuf);
4369 std::string delChrs("abcdefghijklmnopqrstuvwxyz");
4370 int stoiErrorCount = 0;
4371
4372 while(true) {
4373 tagIdx = strBufS.find_first_of(delChrs, prcIdx);
4374 if (tagIdx == std::string::npos)
4375 break;
4376 // std::cout << "suc: " << strBufS.substr(prcIdx) << std::endl;
4377 // std::cout << "tok: " << strBufS.substr(prcIdx, tagIdx-prcIdx) << std::endl;
4378 try {
4379 switch(strBufS[tagIdx]) {
4380 case 'x' : fileWide = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4381 case 'y' : fileTall = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4382 case 'c' : fileChans = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4383 case 'b' : fileBitPerChan = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4384 case 's' : fileIsSGN = (strBufS[prcIdx] == 'S'); fileHasS = true; break;
4385 case 't' : fileIsInt = (strBufS[prcIdx] == 'I'); fileHasT = true; break;
4386 case 'i' : fileIsLTL = (strBufS[prcIdx] == 'L'); fileHasI = true; break;
4387 }
4388 } catch (...) {
4389 stoiErrorCount++;
4390 }
4391 prcIdx=tagIdx+1;
4392 }
4393
4394 int fileBytePerChan = fileBitPerChan / 8;
4395
4396 // std::cout << "fileWide " << fileWide << std::endl;
4397 // std::cout << "fileTall " << fileTall << std::endl;
4398 // std::cout << "fileChans " << fileChans << std::endl;
4399 // std::cout << "fileBitPerChan " << fileBitPerChan << std::endl;
4400 // std::cout << "fileIsSGN " << fileIsSGN << std::endl;
4401 // std::cout << "fileIsInt " << fileIsInt << std::endl;
4402 // std::cout << "fileIsLTL " << fileIsLTL << std::endl;
4403 // std::cout << "fileBytePerChan: " << fileBytePerChan << std::endl;
4404
4405 if (stoiErrorCount > 0)
4406 return 29;
4407
4408 if (fileWide < 0)
4409 return 33;
4410 if (fileTall < 0)
4411 return 34;
4412 if (fileChans < 0)
4413 return 35;
4414 if (fileBitPerChan < 0)
4415 return 36;
4416
4417 if (fileWide == 0)
4418 return 8;
4419 if (fileTall == 0)
4420 return 9;
4421
4422 if (fileWide > intCrdMax)
4423 return 27;
4424 if (fileTall > intCrdMax)
4425 return 28;
4426
4427 resizeCanvas(fileWide, fileTall);
4428
4429 if (fileWide != numPixX)
4430 return(12);
4431 if (fileTall != numPixY)
4432 return(14);
4433
4434 if (!(fileHasT))
4435 fileIsInt = true;
4436
4437 if (!(fileHasS))
4438 fileIsSGN = ( !(fileIsInt)); // If file is missing 's', then assume it's compatable with 't'
4439
4440 if ((colorT::chanIsInt && fileIsSGN))
4441 return 23;
4442
4443 if ((colorT::chanIsInt && !fileIsInt) ||
4444 (colorT::chanIsFloat && fileIsInt))
4445 return 21;
4446
4447 if(fileChans != colorT::channelCount)
4448 return 19;
4449
4450 if(fileBitPerChan != colorT::bitsPerChan)
4451 return 20;
4452
4453 if (!(fileHasI))
4454 fileIsLTL = (platformEndianness() == endianType::LITTLE); // missing 'i', then assume LITTLE.
4455
4456 bool reverseBits = (( fileIsLTL && (platformEndianness() == endianType::BIG)) ||
4457 (!(fileIsLTL) && (platformEndianness() == endianType::LITTLE)));
4458
4459 intCrdT x, y;
4460 bool yNat = !(isIntAxOrientationNaturalY());
4461 bool xNat = isIntAxOrientationNaturalX();
4462 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
4463 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
4464 for(int ci=0; ci<fileChans; ci++) {
4465 if constexpr (colorT::chanIsInt) {
4466 colorChanArithLogType shft = (reverseBits ? colorT::bitsPerChan-8 : 0);
4467 /* Note that colorChanArithLogType is always an unsigned integer type, and thus we avoid compiler errors when trying to use | on a float.
4468 When chanIsInt, colorChanArithLogType is the same as colorChanType when chanIsInt -- so a NOOP because this part of the if only gets
4469 run when chanIsInt. */
4470 colorChanArithLogType pv = 0;
4471 for(int bi=0; bi<fileBytePerChan; bi++) {
4472 colorChanArithLogType uch = (unsigned char)iStream.get();
4473 if (!(iStream.good()))
4474 return 25;
4475 if (iStream.gcount() != 1)
4476 return 25;
4477 pv = pv | static_cast<colorChanArithLogType>(uch << shft);
4478
4479 if (reverseBits)
4480 shft -= 8;
4481 else
4482 shft += 8;
4483 }
4484 getPxColorRefNC(x, y).setChan(ci, static_cast<colorChanType>(pv));
4485 } else {
4486 iStream.read(strBuf, fileBytePerChan);
4487 getPxColorRefNC(x, y).setChan(ci, *((colorChanType*)strBuf));
4488 }
4489 }
4490 }
4491 }
4492 iStream.close();
4493 return 0;
4494 }
4495
4496////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4497 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4498 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4499 int
4501#ifndef MRASTER_FOUND_TIFF
4502 std::cerr << "ERROR: libTIFF no supported: readTIFFfile can't read " << fileName << std::endl;
4503 return 32;
4504#else
4505 TIFF* tif;
4506 uint32_t wTIFF, hTIFF;
4507 uint16_t pmTIFF, pcTIFF, sppTIFF, bpsTIFF, fmtTIFF;
4508
4509 // Open our tiff image
4510 if( !(tif = TIFFOpen(fileName.c_str(), "r")))
4511 return 1;
4512
4513 if(TIFFIsTiled(tif))
4514 return 23;
4515
4516 // All these tags are required -- bail if any are missing.
4517 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wTIFF))
4518 return 2;
4519 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hTIFF))
4520 return 3;
4521 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &sppTIFF))
4522 return 4;
4523 if( 1 != TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &pcTIFF))
4524 return 5;
4525 if( 1 != TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &pmTIFF))
4526 return 6;
4527 if( 1 != TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpsTIFF))
4528 return 7;
4529
4530 // This one is not required. If it's missing, it's 1 (unsigned integer).
4531 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &fmtTIFF))
4532 fmtTIFF = 1;
4533
4534 if (pmTIFF == PHOTOMETRIC_PALETTE)
4535 return 24;
4536
4537 //uint64_t cmTIFF = (1ULL << bpsTIFF) - 1ULL;
4538
4539 // // Dump out image metadata
4540 // std::cerr << "TIFF: " << fileName << std::endl;
4541 // std::cerr << " T WIDTH: " << wTIFF << std::endl;
4542 // std::cerr << " T HEIGHT: " << hTIFF << std::endl;
4543 // std::cerr << " T SPP: " << sppTIFF << std::endl;
4544 // std::cerr << " T PLNC: " << pcTIFF << std::endl;
4545 // std::cerr << " T PHOM: " << pmTIFF << std::endl;
4546 // std::cerr << " T BPS: " << bpsTIFF << std::endl;
4547 // std::cerr << " T MAX: " << cmTIFF << std::endl;
4548 // std::cerr << " T FMT: " << fmtTIFF << std::endl;
4549
4550 // Check file image size and reallocate aRamCanvas
4551 if(wTIFF < 1)
4552 return 8;
4553
4554 if(hTIFF < 1)
4555 return 9;
4556
4557 resizeCanvas(wTIFF, hTIFF);
4558
4559 uint32_t wRC = getNumPixX();
4560
4561 if ((pcTIFF != PLANARCONFIG_CONTIG) && (pcTIFF != PLANARCONFIG_SEPARATE))
4562 return 22;
4563
4564 if(wTIFF != wRC)
4565 return 12;
4566
4567 uint32_t hRC = getNumPixY();
4568
4569 if(hTIFF != hRC)
4570 return 14;
4571
4572 uint16_t sppRC = colorT::channelCount;
4573
4574 // MJR TODO NOTE readTIFFfile: We could read what we can instead of exiting. Check code is in the loop already to do that..
4575 if(sppTIFF != sppRC)
4576 return 19;
4577
4578 uint16_t bpsRC = colorT::bitsPerPixel / sppRC;
4579
4580 if(bpsTIFF != bpsRC)
4581 return 20;
4582
4583 // We only suport SAMPLEFORMAT_UINT & SAMPLEFORMAT_IEEEFP
4584 if ((fmtTIFF != SAMPLEFORMAT_UINT) && (fmtTIFF != SAMPLEFORMAT_IEEEFP))
4585 return 18;
4586
4587 if (( colorType::chanIsInt && (SAMPLEFORMAT_UINT != 1)) ||
4588 (!(colorType::chanIsInt) && (SAMPLEFORMAT_IEEEFP != 3)))
4589 return 21;
4590
4591 bool yNat = !(isIntAxOrientationNaturalY());
4592 bool xNat = isIntAxOrientationNaturalX();
4593 tsize_t scanlinesize = TIFFScanlineSize(tif);
4594 tdata_t scanLineBuffer = _TIFFmalloc(scanlinesize);
4595
4596 if(scanLineBuffer == NULL)
4597 return 16;
4598
4599 if (pcTIFF == PLANARCONFIG_CONTIG) { // Chunky
4600 for(uint32_t row=0; row<hTIFF; row++) {
4601 if( !(TIFFReadScanline(tif, scanLineBuffer, row)))
4602 return 17;
4603 char* p = (char*)(scanLineBuffer);
4604 for(uint32_t col=0; col<wTIFF; col++) {
4605 int x = (xNat ? col : wTIFF-col-1);
4606 int y = (yNat ? row : hTIFF-row-1);
4607 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4608 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4609 p = p + (bpsTIFF/8);
4610 }
4611 }
4612 }
4613 } else if (pcTIFF == PLANARCONFIG_SEPARATE) { // planar
4614 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4615 for(uint32_t row=0; row<hTIFF; row++) {
4616 if( !(TIFFReadScanline(tif, scanLineBuffer, row, samp)))
4617 return 17;
4618 char* p = (char*)(scanLineBuffer);
4619 for(uint32_t col=0; col<wTIFF; col++) {
4620 int x = (xNat ? col : wTIFF-col-1);
4621 int y = (yNat ? row : hTIFF-row-1);
4622 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4623 p = p + (bpsTIFF/8);
4624 }
4625 }
4626 }
4627 }
4628
4629 _TIFFfree(scanLineBuffer);
4630 TIFFClose(tif);
4631 return 0;
4632#endif
4633 }
4634
4635////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4636 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4637 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4638 inline bool
4640#ifndef MRASTER_FOUND_TIFF
4641 return true;
4642#else
4643 return false;
4644#endif
4645 }
4646
4647////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4648 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4649 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4652 double Xo,
4653 double Yo,
4654 double oScale,
4655 colorArgType errorColor,
4656 interpolationType interpMethod) {
4657 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4658 for(intCrdT y=0; y<numPixY; y++) {
4659 for(intCrdT x=0; x<numPixX; x++) {
4660 double xT = (x-Xo);
4661 double yT = (y-Yo);
4662 mjr::point2d<double> fv = f(xT, yT);
4663 double xS = fv.x / oScale + Xo;
4664 double yS = fv.y / oScale + Yo;
4665 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4666 newRamCanvas.drawPointNC(x, y, errorColor);
4667 } else {
4668 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4669 }
4670 }
4671 }
4672 return newRamCanvas;
4673 }
4674
4675////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4676 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4677 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4680 double Xo,
4681 double Yo,
4682 double oScale,
4683 colorArgType errorColor,
4684 interpolationType interpMethod) {
4685 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4686 for(intCrdT y=0; y<numPixY; y++) {
4687 for(intCrdT x=0; x<numPixX; x++) {
4688 double xT = x-Xo;
4689 double yT = y-Yo;
4690 double xS = (HAMatrix[0] * xT + HAMatrix[1] * yT + HAMatrix[2]) / oScale + Xo;
4691 double yS = (HAMatrix[3] * xT + HAMatrix[4] * yT + HAMatrix[5]) / oScale + Yo;
4692 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4693 newRamCanvas.drawPointNC(x, y, errorColor);
4694 } else {
4695 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4696 }
4697 }
4698 }
4699 return newRamCanvas;
4700 }
4701
4702////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4703 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4704 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4707 double rScale,
4708 double Xo,
4709 double Yo,
4710 double oScale,
4711 colorArgType errorColor,
4712 interpolationType interpMethod) {
4713 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4714 for(intCrdT y=0; y<numPixY; y++) {
4715 for(intCrdT x=0; x<numPixX; x++) {
4716 double xT = (x - Xo);
4717 double yT = (y - Yo);
4718 double rT = std::hypot(xT, yT) / rScale;
4719 // double rS = mjr::math::uply::eval(RPoly, rT);
4720 double rS = RPoly[0];
4721 for (unsigned int i=1; i<RPoly.size(); i++)
4722 rS = rS*rT + RPoly[i];
4723 double xS = xT * rS / oScale + Xo;
4724 double yS = yT * rS / oScale + Yo;
4725 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4726 newRamCanvas.drawPointNC(x, y, errorColor);
4727 } else {
4728 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4729 }
4730 }
4731 }
4732 return newRamCanvas;
4733 }
4734
4735////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4736 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4737 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4740 std::vector<double> const& BiPolyY,
4741 double Xo,
4742 double Yo,
4743 double oScale,
4744 colorArgType errorColor,
4745 interpolationType interpMethod) {
4746 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4747 for(intCrdT y=0; y<numPixY; y++) {
4748 for(intCrdT x=0; x<numPixX; x++) {
4749 double xT = (x-Xo);
4750 double yT = (y-Yo);
4751 double xS = mjr::math::bply::eval(BiPolyX, xT, yT) / oScale + Xo;
4752 double yS = mjr::math::bply::eval(BiPolyY, xT, yT) / oScale + Yo;
4753 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4754 newRamCanvas.drawPointNC(x, y, errorColor);
4755 } else {
4756 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4757 }
4758 }
4759 }
4760 return newRamCanvas;
4761 }
4762
4763} // end namespace mjr
4764
4765#define MJR_INCLUDE_ramCanvasTpl
4766#endif
User include file for color types.
Internal include file for ramCanvas types.
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 drawRectangle(pointFltType *thePoints)
interpolationType
Enum for drawing Mode.
void setRealAxOrientationY(realAxisOrientation orientation)
Set the real Y axis orientation.
void drawPoint(fltCrdT x, fltCrdT y)
pointIntType real2int(intCrdT x, intCrdT y)
Convert integer x & y coordinates to real x & y coordinates.
void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3)
void drawLine(pointFltType point1)
void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color)
intAxisOrientation getIntAxOrientationY()
Is the integer Y axis orientation NATURAL?
fltCrdT getCanvasWidY()
height of the display(real coord)
void drawFillRectangle(pointIntType *thePoints, colorArgType color)
std::complex< fltCrdT > cplxFltType
Real coordinate complex type (Provided for convince – not used in ramCanvasTpl)
std::function< colorT(fltCrdT, fltCrdT)> fltCrd2Col
std::function type floating point coordinates to a color
colorT::colorPtrType colorPtrType
colorT: Pointer to color
void drawFillRectangle(pointFltType point1, pointFltType point2, colorArgType color)
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)
std::vector< pointIntType > pointIntVecType
Integer coordinate pair type.
void drawFillRectangle(pointIntType *thePoints)
pointFltType int2real(intCrdT x, intCrdT y)
Convert real x & y coordinates to integer x & y coordinates.
void drawLine(pointFltType point1, pointFltType point2, colorArgType color)
intCrdT statNumNonZeroPixels()
void moveTo(pointIntType thePoint)
void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor)
void adjoinCanvasRight(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
endianType
Endianness Identifiers.
drawModeType drawMode
Drawing mode.
int isOnCanvas(fltCrdT x, fltCrdT y) const
Determine if the given point is within the bounds of the ramCanvasTpl.
void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color)
realAxisOrientation
Enum for real axis orientation.
void drawFillTriangle(pointFltType *thePoints)
void drawPoint(fltCrdT x, fltCrdT y, colorArgType color)
void drawFillTriangle(pointIntType *thePoints)
colorT::maskType colorMaskType
colorT: Mask type
colorChanType getPxColorChanWrap(fltCrdT x, fltCrdT y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
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)
colorT::colorArgType colorArgType
colorT: Argument passing type
void drawFillTriangle(pointFltType *thePoints, colorArgType color)
colorT::csNatType csNatType
colorT: Color Scheme Natural Type
colorChanType getPxColorChanWrap(pointIntType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
colorT::colorCRefType colorCRefType
colorT: Const Ref to a color
void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color)
void drawLine(pointFltType point1, pointFltType point2)
intAxisOrientation intAxOrientationX
Flip horizontally.
void drawPoint(intCrdT x, intCrdT y)
void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3)
void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
drawModeType
Enum for drawing Mode.
void setDefaultDrawMode()
Set the default draw mode.
fltCrdT canvasWidY
height of the canvas (real coord)
void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3)
void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color)
colorT dfltColor
Default color.
void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc)
void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3)
fltCrdT canvasWidX
Width of the canvas (real coord)
colorT::channelType colorChanType
colorT: Channel type
colorT::channelArithLogType colorChanArithLogType
colorT: Channel arithmatic (Int: ^|&~)
void drawLine(pointIntType point1)
void drawTriangle(pointIntType *thePoints, colorArgType color)
void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
colorT getPxColor(intCrdT x, intCrdT y) const
Returns a copy of the color at the given coordinates.
void drawFillTriangle(pointIntType *thePoints, colorArgType color)
colorT::channelArithDType colorChanArithDType
colorT: Channel arithmatic (Int: -)
intCrdT dfltY
y coordinate used by default.
colorT * pixels
Array to hold the color values.
colorT::channelArithSDPType colorChanArithSDPType
colorT: Channel arithmatic (Int: +-*)
fltCrdT minRealX
x coord of min (real coord)
intCrdT realDelta2intX(fltCrdT x) const
Convert real distance on the x coordinate axis to an integral distance.
fltCrdT getCanvasWidD()
Width of the display (real coord)
void setDfltColor(std::string cornerColor)
void setDrawMode(drawModeType newDrawMode)
Set the current drawing mode NOOP if enableDrawModes is false.
void setDfltColor(const char *cornerColor)
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.
colorChanType getPxColorChanWrap(pointFltType thePoint) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawPointS(intCrdT x, intCrdT y, colorArgType color)
Draw a point without any special drawing options.
void drawPoint(pointIntType thePoint)
colorT * iterator
pixel store iterators
void drawLine(pointIntType point1, pointIntType point2)
void setRealAxOrientationX(realAxisOrientation orientation)
Set the real X axis orientation.
void moveTo(pointFltType thePoint)
fltCrdT maxRealX
x coord of max (real coord)
bool isNotSameSize(ramCanvasTpl const &inRC) const
Return true if given canvas and current canvas are NOT the same size.
fltCrdT getMaxRealY()
y coord of max (real coord)
realAxisOrientation getRealAxOrientationX()
Get the real X axis orientation.
void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color)
void drawHorzLineNC(intCrdT xMin, intCrdT xMax, intCrdT yConst, colorArgType color)
Draw a horizontal line with no clipping or bounds checking.
fltCrdT minRealY
y coord of min (real coord)
void setDfltColor(colorArgType color)
Set the default color.
void moveTo(intCrdT x, intCrdT y)
Set the current default point to the given coordinates.
void drawCircle(pointFltType centerPoint, fltCrdT radiusX)
colorT * pixelsE
Point one beyond end of pixels array.
void drawTriangle(pointFltType *thePoints, colorArgType color)
fltCrdT getMaxRealX()
x coord of max (real coord)
realAxisOrientation realAxOrientationX
Orientation of x axis.
point2d< fltCrdT > pointFltType
Real coordinate pair type.
void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color)
void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color)
fltCrdT maxRealY
y coord of max (real coord)
bool isIntAxOrientationNaturalY()
Get the integer Y axis orientation.
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)
int isCliped(intCrdT x, intCrdT y) const
void drawPointNC(intCrdT x, intCrdT y, colorArgType color)
The functions here work in a similar way to the non-NC functions, but with no clipping or bounds chec...
fltCrdT pixWidY
Height of a pixel (real coord)
void drawRectangle(pointFltType *thePoints, colorArgType color)
void setRealAxisDefaultOrientation()
Set the real axis orientation to default (NATURAL for both X and Y axes)
void drawStringBox(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc)
colorT getPxColor(fltCrdT x, fltCrdT y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
colorT::cmfInterpolationEnum cmfInterpolationEnum
colorT: Interpolation for color match functions
colorT::cornerColorEnum colorCornerEnum
colorT: RGB Color Corners
void drawFillTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3)
void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color)
fltCrdT getPixWidX()
Width of a pixel (real coord)
void drawFillRectangle(pointFltType point1, pointFltType point2)
void drawRectangle(pointFltType point1, pointFltType point2)
void drawTriangle(pointFltType *thePoints)
void drawCircle(pointIntType centerPoint, intCrdT radiusX)
void setDfltColor(colorChanType r, colorChanType g, colorChanType b)
void drawLine(pointIntType point1, pointIntType point2, colorArgType color)
point2d< intCrdT > pointIntType
Integer coordinate pair type.
void drawPoint(pointFltType thePoint)
intCrdT coordIntType
Integer type for coordinates.
intCrdT numPixX
Number of x pixels.
fltCrdT int2realSideY(intCrdT y, int side)
Given integer y coordinate, produce real y coordinate for one of the pixel's edge.
realAxisOrientation realAxOrientationY
Orientation of y axis.
colorT::csFltType csFltType
colorT: Color Scheme Float Type
int isCliped(fltCrdT x, fltCrdT y) const
Determine if the given point is within the bounds of the ramCanvasTpl.
void drawRectangle(pointIntType point1, pointIntType point2, colorArgType color)
void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX)
intAxisOrientation intAxOrientationY
Flip vertically.
void combineRamCanvasMean(ramCanvasTpl *theCanvasList, const int N)
Take a list of ramCanvasTpl objects and combine them with the current ramCanvasTpl using mean.
void moveTo(fltCrdT x, fltCrdT y)
void setIntAxOrientationX(intAxisOrientation orientation)
Set the integer X axis orientation.
intCrdT realDelta2intY(fltCrdT y) const
Convert real distance on the y coordinate axis to an integral distance.
intCrdT numPixY
Number of y pixels.
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, intCrdT x1=0, intCrdT y1=0)
Draw the given canvas at the indicated point.
void drawCircle(fltCrdT radiusX)
colorT::channelArithFltType colorChanArithFltType
colorT: Channel arithmatic (Flt: +-*)
colorT getPxColorNC(intCrdT x, intCrdT y) const
Get the default point to the specified coordinates with no clipping or bounds checking.
colorT::colorRefType colorRefType
colorT: Ref to a color
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...
fltCrdT pixWidX
Width of a pixel (real coord)
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)
colorT * pixelIterator
pixel store iterators
void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color)
void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2)
void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX)
int isOnCanvas(intCrdT x, intCrdT y) const
std::function< colorT(pointIntType)> intPnt2Col
std::function type int point point to a color
void drawPoint(colorArgType color)
colorT colorType
Color type for pixels.
void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color)
intCrdT dfltX
x coordinate used by default.
fltCrdT coordFltType
Real type for coordinates.
fltCrdT getPixWidY()
Height of a pixel (real coord)
void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color)
realAxisOrientation getRealAxOrientationY()
Get the real Y axis orientation.
bool isClose(ramCanvasTpl const &inRC, colorChanType epsilon) const
Return true if corresponding pixels in each canvas are "close" as defined by colorTpl::isClose().
void drawCircle(intCrdT radiusX)
void drawTriangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, fltCrdT x3, fltCrdT y3, colorArgType color)
intCrdT getNumPixX() const
intCrdT getNumPixY() const
fltCrdT getMinRealX()
x coord of min (real coord)
void drawRectangle(pointIntType point1, pointIntType point2)
void drawTriangle(pointIntType *thePoints)
void drawPoint(intCrdT x, intCrdT y, colorArgType color)
Draw a point at the specified coordinates with the specified color.
void setIntAxOrientationY(intAxisOrientation orientation)
Set the integer Y axis orientation.
std::complex< intCrdT > cplxIntType
Integer coordinate complex type (Provided for convince – not used in ramCanvasTpl)
std::function< colorT(pointFltType)> fltPnt2Col
std::function type floating point point to a color
void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2)
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 drawFillCircle(intCrdT radiusX)
void adjoinCanvasBottom(const ramCanvasTpl &theCanvas)
Adjoin the canvas to the side of the current canvas.
colorT::csIntType csIntType
colorT: Color Scheme Integer Type
intCrdT numPix
Number of pixels.
void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color)
void drawPoint(pointIntType thePoint, colorArgType color)
void drawFillRectangle(pointIntType point1, pointIntType point2)
intAxisOrientation
Enum for integer axis orientation.
colorT * getPixels()
Returns a pointer to the raw pixel store.
colorT::colorSpaceEnum colorSpaceEnum
colorT: Color spaces
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.
std::function< colorT(intCrdT, intCrdT)> intCrd2Col
std::function type int point coordinates to a color
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 setIntAxisDefaultOrientation()
Set the integer axis orientation to default (NATURAL for both X and Y axes)
colorT::channelArithSPType colorChanArithSPType
colorT: Channel arithmatic (Int: +*)
fltCrdT getMinRealY()
y coord of min (real coord)
void drawLine(pointIntType point1, colorArgType color)