MRaster lib 22.0.0.0
Image Processing Library
Loading...
Searching...
No Matches
ramCanvasTpl.hpp
Go to the documentation of this file.
1// -*- Mode:C++; Coding:us-ascii-unix; fill-column:158 -*-
2/*******************************************************************************************************************************************************.H.S.**/
3/**
4 @file ramCanvasTpl.hpp
5 @author Mitch Richling <https://www.mitchr.me>
6 @brief Internal include file for ramCanvas types.@EOL
7 @copyright
8 @parblock
9 Copyright (c) 1988-2015, Mitchell Jay Richling <https://www.mitchr.me> All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
12
13 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
14
15 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17
18 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software
19 without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 DAMAGE.
27 @endparblock
28 @filedetails
29 Note that this file is not intended for inclusion into end user application code; however, this use is quite possible in some special cases. For a less
30 complex interface, one is encouraged to include the ramCanvas.h include file instead.
31*/
32/*******************************************************************************************************************************************************.H.E.**/
33
34#ifndef MJR_INCLUDE_ramCanvasTpl
35
36////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
37#include "MRcolor.hpp"
38#include "hersheyFont.hpp"
39#include "MRpoint2d.hpp"
40
41#include "MRMathIVL.hpp"
42#include "MRMathFC.hpp"
43#include "MRMathODR.hpp"
44#include "MRMathBPLY.hpp"
45
46////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
47#ifdef MRASTER_FOUND_TIFF
48#include <unistd.h> /* UNIX std stf POSIX */
49#include <tiffio.h> /* libTIFF libTIFF */
50#endif
51
52////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
53#include <algorithm> /* STL algorithm C++11 */
54#include <chrono> /* time C++11 */
55#include <cmath> /* std:: C math.h C++11 */
56#include <complex> /* Complex Numbers C++11 */
57#include <cstdint> /* std:: C stdint.h C++11 */
58#include <fstream> /* C++ fstream C++98 */
59#include <functional> /* STL funcs C++98 */
60#include <iomanip> /* C++ stream formatting C++11 */
61#include <iostream> /* C++ iostream C++11 */
62#include <iterator> /* STL Iterators C++11 */
63#include <list> /* STL list C++11 */
64#include <map> /* STL map C++11 */
65#include <numbers> /* C++ math constants C++20 */
66#include <random> /* C++ random numbers C++11 */
67#include <sstream> /* C++ string stream C++ */
68#include <stdexcept> /* Exceptions C++11 */
69#include <string> /* C++ strings C++11 */
70#include <type_traits> /* C++ metaprogramming C++11 */
71#include <utility> /* STL Misc Utilities C++11 */
72#include <vector> /* STL vector C++11 */
73
74////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
75// Put everything in the mjr namespace
76namespace mjr {
77 /** @brief Class providing off-screen drawing functionality.@EOL
78
79 This class essentially manages a 2D array of pixels (represented as colorTpl objects). Both integer and floating point coordinates are supported.
80
81 Coordinates
82 ===========
83
84 Traditional Mathematical Coordinate System
85 ------------------------------------------
86
87 The traditional coordinate system used in mathematics is the Cartesian Coordinate system. In this system the axes represent real numbers which increase as
88 one moves to the right or up.
89
90
91 ^ y (increasing upward)
92 |
93 . (0, 1)
94 |
95 |
96 |
97 (-1,0) | (0,0) x (increasing to the right)
98 <-.--------+--------.----->
99 | (1,0)
100 |
101 |
102 |
103 . (0, -1)
104 |
105 v
106
107 Traditional Computer Graphics Coordinate System
108 -----------------------------------------------
109
110 Unlike the Cartesian coordinate system, the traditional coordinates used in computer graphics have only positive, integer coordinates, the origin at the upper
111 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
112 typical layout of 2D arrays in RAM.
113
114
115 (0,0) +------------+ (numPixX-1, 0)
116 | |
117 | |
118 | |
119 | |
120 | |
121 (numPixY-1, 0) +------------+ (numPixX-1, numPixY-1)
122
123 ramCanvas Coordinate Systems
124 ----------------------------
125
126 This library supports two sets of coordinates for each image:
127
128 - Integer -- much like traditional computer graphics coordinates
129 - Floating Point -- much like mathematical coordinates
130
131 The integer coordinates are a generalization of the traditional integer coordinates used for computer graphics. Like the traditional system, they are
132 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
133 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
134 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
135 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
136 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
137 writeRAWfile.
138
139 @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
140 @tparam colorT A type for the image pixels (a color)
141 @tparam fltCrdT A floating point type used for the floating point image coordinates
142 @tparam enableDrawModes If true, enables drawing modes other than drawModeType::SET. */
143 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
144 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
146 public:
147
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 /** @name Handy ramCanvasTpl converter classes. */
150 //@{
151 //--------------------------------------------------------------------------------------------------------------------------------------------------------
152 /** This class is an incomplete rcConverter (no getPxColorNC method) that provides a nice base for homogenious rcConverters. */
153 template<class inRamCanvasT>
155 public:
156 inRamCanvasT& attachedRC;
157 rcConverterHomoBase(inRamCanvasT& aRC) : attachedRC(aRC) { }
158 inline bool isIntAxOrientationNaturalX() { return attachedRC.isIntAxOrientationNaturalX(); }
159 inline bool isIntAxOrientationNaturalY() { return attachedRC.isIntAxOrientationNaturalY(); }
160 inline typename inRamCanvasT::coordIntType getNumPixX() { return attachedRC.getNumPixX(); }
161 inline typename inRamCanvasT::coordIntType getNumPixY() { return attachedRC.getNumPixY(); }
162 };
163 //--------------------------------------------------------------------------------------------------------------------------------------------------------
164 template<class inRamCanvasT>
165 class rcConverterIdentity : public rcConverterHomoBase<inRamCanvasT> {
166 public:
167 rcConverterIdentity(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
168 typedef typename inRamCanvasT::colorType colorType;
169 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y); }
170 };
171 //--------------------------------------------------------------------------------------------------------------------------------------------------------
172 template<class inRamCanvasT>
173 class rcConverterRGBbyte : public rcConverterHomoBase<inRamCanvasT> {
174 public:
175 rcConverterRGBbyte(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
176 typedef typename inRamCanvasT::colorType::colConRGBbyte colorType;
177 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGB_byte(); }
178 };
179 //--------------------------------------------------------------------------------------------------------------------------------------------------------
180 template<class inRamCanvasT>
182 public:
183 rcConverterRGBAbyte(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
184 typedef typename inRamCanvasT::colorType::colConRGBAbyte colorType;
185 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGBA_byte(); }
186 };
187 //--------------------------------------------------------------------------------------------------------------------------------------------------------
188 template<class inRamCanvasT>
190 public:
191 rcConverterRGBdbl(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
192 typedef typename inRamCanvasT::colorType::colConRGBdbl colorType;
193 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGB_dbl(); }
194 };
195 //--------------------------------------------------------------------------------------------------------------------------------------------------------
196 template<class inRamCanvasT>
198 public:
199 rcConverterRGBAdbl(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
200 typedef typename inRamCanvasT::colorType::colConRGBAdbl colorType;
201 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getColConRGBA_dbl(); }
202 };
203 //--------------------------------------------------------------------------------------------------------------------------------------------------------
204 /** Colorize a ramCanvasTpl with integer channels using a color scheme. */
205 template<class inRamCanvasT, class outColorT, class colorScheme, bool clamp, int factor, int chan>
206 class rcConverterColorScheme : public rcConverterHomoBase<inRamCanvasT> {
207 public:
208 rcConverterColorScheme(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
209 typedef outColorT colorType;
210 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) {
211 typename outColorT::csIntType csi = static_cast<typename outColorT::csIntType>(rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).getChan(chan) * factor);
212 if (clamp)
213 csi = mjr::math::ivl::clamp(csi, colorScheme::numC-1);
214 return colorScheme::c(csi);
215 }
216 };
217 //--------------------------------------------------------------------------------------------------------------------------------------------------------
218 /** Convert a ramCanvasTpl to a greyscale image using colorT::intensity(). */
219 template<class inRamCanvasT, class outColorChanT>
220 class rcConverterMonoIntensity : public rcConverterHomoBase<inRamCanvasT> {
221 public:
222 rcConverterMonoIntensity(inRamCanvasT& aRC) : rcConverterHomoBase<inRamCanvasT>(aRC) { }
224 inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) {
225 return static_cast<outColorChanT>(rcConverterHomoBase<inRamCanvasT>::attachedRC.getPxColorNC(x, y).intensity());
226 }
227 };
228 //@}
229
230 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
231 /** @name Typedefs related to template parameters */
232 //@{
233 typedef point2d<fltCrdT> pointFltType; //!< Real coordinate pair type
234 typedef point2d<intCrdT> pointIntType; //!< Integer coordinate pair type
235 typedef std::vector<pointIntType> pointIntVecType; //!< Integer coordinate pair type
236 typedef std::complex<fltCrdT> cplxFltType; //!< Real coordinate complex type (Provided for convince -- not used in ramCanvasTpl)
237 typedef std::complex<intCrdT> cplxIntType; //!< Integer coordinate complex type (Provided for convince -- not used in ramCanvasTpl)
238 typedef intCrdT coordIntType; //!< Integer type for coordinates
239 typedef fltCrdT coordFltType; //!< Real type for coordinates
240 typedef colorT colorType; //!< Color type for pixels
241 //@}
242
243 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
244 /** @name Typedefs related to colorT */
245 //@{
246 typedef typename colorT::channelType colorChanType; //!< colorT: Channel type
247 typedef typename colorT::maskType colorMaskType; //!< colorT: Mask type
248 typedef typename colorT::channelArithDType colorChanArithDType; //!< colorT: Channel arithmatic (Int: -)
249 typedef typename colorT::channelArithSPType colorChanArithSPType; //!< colorT: Channel arithmatic (Int: +*)
250 typedef typename colorT::channelArithSDPType colorChanArithSDPType; //!< colorT: Channel arithmatic (Int: +-*)
251 typedef typename colorT::channelArithFltType colorChanArithFltType; //!< colorT: Channel arithmatic (Flt: +-*)
252 typedef typename colorT::channelArithLogType colorChanArithLogType; //!< colorT: Channel arithmatic (Int: ^|&~)
253 typedef typename colorT::colorSpaceEnum colorSpaceEnum; //!< colorT: Color spaces
254 typedef typename colorT::cornerColorEnum colorCornerEnum; //!< colorT: RGB Color Corners
255 typedef typename colorT::colorArgType colorArgType; //!< colorT: Argument passing type
256 typedef typename colorT::colorPtrType colorPtrType; //!< colorT: Pointer to color
257 typedef typename colorT::colorRefType colorRefType; //!< colorT: Ref to a color
258 typedef typename colorT::colorCRefType colorCRefType; //!< colorT: Const Ref to a color
259 typedef typename colorT::csIntType csIntType; //!< colorT: Color Scheme Integer Type
260 typedef typename colorT::csFltType csFltType; //!< colorT: Color Scheme Float Type
261 typedef typename colorT::csNatType csNatType; //!< colorT: Color Scheme Natural Type
262 typedef typename colorT::cmfInterpolationEnum cmfInterpolationEnum; //!< colorT: Interpolation for color match functions
263 //@}
264
265 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
266 /** @name Iterator Typedefs */
267 //@{
268 typedef colorT* pixelIterator; //!< pixel store iterators
269 typedef colorT* iterator; //!< pixel store iterators
270 //@}
271
272 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
273 /** @name Enumerations */
274 //@{
275 /** Enum for real axis orientation */
276 enum class realAxisOrientation { INVERTED, //!< Real axis is inverted with respect to the integer axis
277 NATURAL //!< Real axis is not inverted with respect to the integer axis
278 };
279
280 /** Enum for integer axis orientation.
281
282 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
283 array. The integer axis orientation is used to arrange the pixels when a canvas is saved/loaded to/from an image file. */
284 enum class intAxisOrientation { INVERTED, //!< Zero is to the right or bottom
285 NATURAL //!< Zero is to the left or top
286 };
287
288 /** Enum for drawing Mode */
289 enum class drawModeType { SET, //!< Simply set the pixel value to the new value
290 XOR, //!< See: tfrmXor()
291 ADDCLAMP, //!< See: tfrmAddClamp()
292 AND, //!< See: tfrmAnd()
293 OR, //!< See: tfrmOr()
294 DIFFCLAMP, //!< See: tfrmDiffClamp()
295 MULTCLAMP //!< See: tfrmMultClamp()
296 };
297
298 /** Enum for drawing Mode */
299 enum class interpolationType { BILINEAR, //!< bilinear
300 TRUNCATE, //!< Coordinates are truncated (fractional bits chopped off)
301 NEAREST, //!< Coordinates are rounded
302 AVERAGE4, //!< Average of four sourounding pixels
303 AVERAGE9 //!< Average of 9 sourounding pixels
304 };
305
306 //@}
307
308 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
309 /** @name Logical Maximum for intCrdT values */
310 //@{
311 const static intCrdT intCrdMax = (1ul << ((sizeof(intCrdT)*CHAR_BIT-1)/2)) - 3; //!< maximum for numPixX, numPixY, & numPix.
312 //@}
313
314 private:
315
316 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
317 /** @name Private Enumerations */
318 //@{
319 /** Endianness Identifiers. */
320 enum class endianType {
321 BIG, //!< PowerPC
322 LITTLE, //!< Intel
323 AUTO //!< Whatever the platform uses
324 };
325 //@}
326
327 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
328 /** @name intCrd Guard Valus */
329 //@{
330 const static intCrdT intCrdGrdMax = intCrdMax+1; //!< Large sentinel value (always off canvas)
331 const static intCrdT intCrdGrdMin = -1; //!< Small sentinel value (always off canvas)
332 //@}
333
334 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
335 /** @name Canvas integer coordinates */
336 //@{
337 intCrdT numPixX; //!< Number of x pixels
338 intCrdT numPixY; //!< Number of y pixels
339 intCrdT numPix; //!< Number of pixels
340 //@}
341
342 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
343 /** @name Canvas real coordinates */
344 //@{
345 fltCrdT minRealX; //!< x coord of min (real coord)
346 fltCrdT maxRealX; //!< x coord of max (real coord)
347 fltCrdT minRealY; //!< y coord of min (real coord)
348 fltCrdT maxRealY; //!< y coord of max (real coord)
349 //@}
350
351 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
352 /** @name Canvas real/integer coordinates conversion */
353 //@{
354 fltCrdT pixWidX; //!< Width of a pixel (real coord)
355 fltCrdT pixWidY; //!< Height of a pixel (real coord)
356
357 fltCrdT canvasWidX; //!< Width of the canvas (real coord)
358 fltCrdT canvasWidY; //!< height of the canvas (real coord)
359 //@}
360
361 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
362 /** @name Axis orientation */
363 //@{
364 realAxisOrientation realAxOrientationX; //!< Orientation of x axis
365 realAxisOrientation realAxOrientationY; //!< Orientation of y axis
366 intAxisOrientation intAxOrientationX; //!< Flip horizontally
368 //@}
369
370 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
371 /** @name Canvas pixel store pointers */
372 //@{
373 colorT *pixels; //!< Array to hold the color values.
374 colorT *pixelsE; //!< Point one beyond end of pixels array.
375 //@}
376
377 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
378 /** @name Drawing defaults */
379 //@{
380 colorT dfltColor; //!< Default color.
381 drawModeType drawMode; //!< Drawing mode.
382 intCrdT dfltX; //!< x coordinate used by default.
383 intCrdT dfltY; //!< y coordinate used by default.
384 //@}
385
386 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
387 /** @name Filled Triangle Utility Functions */
388 //@{
389 //--------------------------------------------------------------------------------------------------------------------------------------------------------
390 /** Utliity function behind the drawFillTriangle() functions.
391 @bug Not thread safe
392 @param x1 The x coordinate of the first point
393 @param y1 The y coordinate of the first point
394 @param x2 The x coordinate of the second point
395 @param y2 The y coordinate of the second point
396 @param x3 The x coordinate of the third point
397 @param y3 The y coordinate of the third point
398 @param c1 The color of the first point (x1, y1)
399 @param c2 The color of the second point (x2, y2)
400 @param c3 The color of the third point (x3, y3)
401 @param solid Use only c1 if true, otherwise use barycentric interpolation */
402 void drawFillTriangleUtl(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorT c1, colorT c2, colorT c3, bool solid);
403 //@}
404
405 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
406 /** @name File Writing Utility Methods */
407 //@{
408 //--------------------------------------------------------------------------------------------------------------------------------------------------------
409 /** Write an unsigned integer to a stream with given length and endianness.
410 @param oStream The ostream object to which to write
411 @param endianness The endianness to use for the integer.
412 @param numBytes The number of bytes of the data parameter to use (logically the least significant bits)
413 @param data The integer to write */
414 void writeUIntToStream(std::ostream& oStream, endianType endianness, int numBytes, uint64_t data);
415 //--------------------------------------------------------------------------------------------------------------------------------------------------------
416 /** Determine the platform's endianness. */
417 endianType platformEndianness();
418 //@}
419
420 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
421 /** @name Coordinate System Manipulation (i) */
422 //@{
423 //--------------------------------------------------------------------------------------------------------------------------------------------------------
424 /** Several internal parameters are maintained within this class that make conversion between real coordinates and integer coordinate very fast. This
425 function will update the internal parameters if the real coordinate sizes or the integer coordinate sizes have changed. This function is intended for
426 internal use. An example of when to use this function is right after the integer coordinate axes have changed via a call to newIntCoordsNC(). */
427 void updRealCoords();
428 //--------------------------------------------------------------------------------------------------------------------------------------------------------
429 /** Change the logical coordinate sizes.
430 It is important that the specified coordinate sizes describe an image with FEWER pixels than the previous sizes. This function will NOT allocate a
431 new pixel array, so the previous array contents will be interpreted as valid data -- just at different coordinates. This function causes no memory
432 leaks. This function will NOT update the internal parameters related to real coordinate systems and so updRealCoords() should be called after this
433 function in most cases. This function is intended for internal use and provides no safety checks.
434 @param numPixX_p The width of the new canvas
435 @param numPixY_p The height of the new canvas */
436 void newIntCoordsNC(intCrdT numPixX_p, intCrdT numPixY_p);
437 //@}
438
439 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
440 /** @name Plane Manipulation Methods */
441 //@{
442 //--------------------------------------------------------------------------------------------------------------------------------------------------------
443 /** Destroy the current pixel memory and reallocate a new pixel space of the given size.
444 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
445 new canvas if either argument is zero or less. Updates coordinates.
446 @param numPixX_p The width of the new canvas
447 @param numPixY_p The height of the new canvas */
448 void reallocCanvas(intCrdT numPixX_p, intCrdT numPixY_p);
449 //--------------------------------------------------------------------------------------------------------------------------------------------------------
450 /** Free the pixel memory (i) */
451 void freeCanvas();
452 //--------------------------------------------------------------------------------------------------------------------------------------------------------
453 /** Points the pixels pointer at a new pixel store, and updates coordinates. Pixels pointer not changed if new_pixels is NULL */
454 void rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY);
455 //@}
456
457 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
458 /** @name Various helper functions */
459 //@{
460 //--------------------------------------------------------------------------------------------------------------------------------------------------------
461 /** Used to find the left and right edges of a triangle. */
462 void triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin);
463 //@}
464
465 public:
466
467 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
468 /** @name Raster Data Import And Export. */
469 //@{
470 //--------------------------------------------------------------------------------------------------------------------------------------------------------
471 /** Extract raster data from the image, and pack it into a typical form used by imaging applications.
472
473 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.
474 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
475 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
476 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,
477 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:
478
479 Examples of how to pack various common raster data formats
480 ..........RGB RGBA ARGB BGR ABGR Grey
481 redChan 0 0 1 2 3 0
482 greenChan 1 1 2 1 2 -1
483 blueChan 2 2 3 0 1 -1
484 alphaChan -1 3 0 -1 0 -1
485
486 @param rasterData Unsigned char pointer to image data. If NULL,then data will be allocated for image.
487 @param x1 First x coordinate first corner of sub-image to extract
488 @param x2 First x coordinate second corner of sub-image to extract
489 @param y1 First y coordinate first corner of sub-image to extract
490 @param y2 First y coordinate second corner of sub-image to extract
491 @param redChan Channel index to use for red
492 @param blueChan Channel index to use for blue
493 @param greenChan Channel index to use for green
494 @param alphaChan Channel index to use for alpha*/
495 int exportRasterData(void* &rasterData, intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, int redChan, int greenChan, int blueChan, int alphaChan);
496 //@}
497
498 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
499 /** @name Constructors & Assignment Operators */
500 //@{
501 //--------------------------------------------------------------------------------------------------------------------------------------------------------
502 /** No arg constructor. Sets numPixX and numPixY to -1, and pixels to NULL. */
503 ramCanvasTpl();
504 //--------------------------------------------------------------------------------------------------------------------------------------------------------
505 /** Copy constructor */
506 ramCanvasTpl(const ramCanvasTpl &theCanvas);
507 //--------------------------------------------------------------------------------------------------------------------------------------------------------
508 /** Most commonly used constructor.
509 The real coordinates have default values with -1 as the min values and 1 used as the max values.
510 @param numPixX_p Number of pixels in the X direction
511 @param numPixY_p Number of pixels in the Y direction
512 @param minRealX_p Minimum real x coordinate value
513 @param maxRealX_p Maximum real x coordinate value
514 @param minRealY_p Minimum real y coordinate value
515 @param maxRealY_p Maximum real y coordinate value */
516 ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p=-1, fltCrdT maxRealX_p=1, fltCrdT minRealY_p=-1, fltCrdT maxRealY_p=1);
517 //--------------------------------------------------------------------------------------------------------------------------------------------------------
518 /** Move constructor */
519 ramCanvasTpl(ramCanvasTpl&& theCanvas);
520 //--------------------------------------------------------------------------------------------------------------------------------------------------------
521 /** Move assignment operator */
522 ramCanvasTpl& operator=(ramCanvasTpl&& theCanvas);
523 //@}
524
525 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
526 /** @name Destructor */
527 //@{
528 /** Destructor deallocates memory for the canvas. */
530 //@}
531
532
533 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
534 /** @name Canvas Compositing
535
536 @warning These functions are experimental! Functionality and API are likely to change in the future.
537
538 */
539 //@{
540 //--------------------------------------------------------------------------------------------------------------------------------------------------------
541 /** Adjoin the canvas to the side of the current canvas.
542
543 @warning This function is experimental! Functionality and API are likely to change in the future.
544
545 @param theCanvas The canvas to adjoin. */
546 void adjoinCanvasRight(const ramCanvasTpl &theCanvas) {
547 intCrdT origNumPixX = getNumPixX();
548 expandCanvas(origNumPixX + theCanvas.getNumPixX(), std::max(getNumPixY(), theCanvas.getNumPixY()));
549 insertCanvas(theCanvas, origNumPixX);
550 }
551 //--------------------------------------------------------------------------------------------------------------------------------------------------------
552 /** Adjoin the canvas to the side of the current canvas.
553
554 @warning This function is experimental! Functionality and API are likely to change in the future.
555
556 @param theCanvas The canvas to adjoin. */
557 void adjoinCanvasLeft(const ramCanvasTpl &theCanvas) {
558 intCrdT origNumPixX = getNumPixX();
559 expandCanvas(origNumPixX + theCanvas.getNumPixX(), std::max(getNumPixY(), theCanvas.getNumPixY()), origNumPixX);
560 insertCanvas(theCanvas);
561 }
562 //--------------------------------------------------------------------------------------------------------------------------------------------------------
563 /** Adjoin the canvas to the side of the current canvas.
564
565 @warning This function is experimental! Functionality and API are likely to change in the future.
566
567 @param theCanvas The canvas to adjoin. */
568 void adjoinCanvasBottom(const ramCanvasTpl &theCanvas) {
569 intCrdT origNumPixY = getNumPixY();
570 expandCanvas(std::max(getNumPixX(), theCanvas.getNumPixX()), origNumPixY + theCanvas.getNumPixY(), 0, origNumPixY);
571 insertCanvas(theCanvas, 0, 0);
572 }
573 //--------------------------------------------------------------------------------------------------------------------------------------------------------
574 /** Adjoin the canvas to the side of the current canvas.
575
576 @warning This function is experimental! Functionality and API are likely to change in the future.
577
578 @param theCanvas The canvas to adjoin. */
579 void adjoinCanvasTop(const ramCanvasTpl &theCanvas) {
580 intCrdT origNumPixY = getNumPixY();
581 expandCanvas(std::max(getNumPixX(), theCanvas.getNumPixX()), origNumPixY + theCanvas.getNumPixY());
582 insertCanvas(theCanvas, 0, origNumPixY);
583 }
584 //--------------------------------------------------------------------------------------------------------------------------------------------------------
585 /** Draw the given canvas at the indicated point.
586
587 @warning This function is experimental! Functionality and API are likely to change in the future.
588
589 @param theCanvas The canvas to draw on the current canvas.
590 @param x1 X coordinate at which to place the canvas.
591 @param y1 Y coordinate at which to place the canvas. */
592 void insertCanvas(const ramCanvasTpl &theCanvas, intCrdT x1 = 0, intCrdT y1 = 0) {
593 for(intCrdT y=0; y<theCanvas.getNumPixY(); y++)
594 for(intCrdT x=0; x<theCanvas.getNumPixX(); x++)
595 drawPoint(x1+x, y1+y, theCanvas.getPxColorRefNC(x, y));
596 }
597 //@}
598
599 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
600 /** @name Canvas resize and crop */
601 //@{
602 //--------------------------------------------------------------------------------------------------------------------------------------------------------
603 /** Resize the canvas to the given size.
604 Contents of new canvas may be random data. Not guarnteed to reallocate the canvas.
605 @param new_numPixX_p The width of the new canvas
606 @param new_numPixY_p The height of the new canvas */
607 void resizeCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p);
608 //--------------------------------------------------------------------------------------------------------------------------------------------------------
609 /** Expand the current canvas.
610 The current image will appear within the new canvas at the specified location. All pixels not set by the previous image
611 will be set to the given color.
612 @param new_numPixX_p The width of the new canvas
613 @param new_numPixY_p The height of the new canvas
614 @param x1 Coord at which the left of the old image will appear in the new image
615 @param y1 Coord at which the top of the old image will appear in the new image
616 @param color Color to use for the background of the new image. */
617 void expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1 = 0, intCrdT y1 = 0, colorArgType color = colorT(colorT::minChanVal));
618 //--------------------------------------------------------------------------------------------------------------------------------------------------------
619 /** This function will crop the canvas to the given rectangular region.
620 @param x1 Left, or right, edge of region to keep.
621 @param x2 Right, or left, edge of region to keep.
622 @param y1 Left, or right, edge of region to keep.
623 @param y2 Right, or left, edge of region to keep. */
624 void cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2);
625 //@}
626
627 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
628 /** @name Coordinate System Manipulation */
629 //@{
630 /** Change the real coordinate system associated with a canvas.
631 It updates all internal parameters are required.
632 @param minRealX_p Minimum real x coordinate value
633 @param maxRealX_p Maximum real x coordinate value
634 @param minRealY_p Minimum real y coordinate value
635 @param maxRealY_p Maximum real y coordinate value */
636 void newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p);
637 //@}
638
639 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
640 /** @name Canvas comparison */
641 //@{
642 //--------------------------------------------------------------------------------------------------------------------------------------------------------
643 /** Return true if given canvas and current canvas are the same size. */
644 inline bool isSameSize(ramCanvasTpl const & inRC) const {
645 if ((numPixY == inRC.getNumPixY()) && (numPixX == inRC.getNumPixX()))
646 return true;
647 else
648 return false;
649 }
650 //--------------------------------------------------------------------------------------------------------------------------------------------------------
651 /** Return true if given canvas and current canvas are *NOT* the same size. */
652 inline bool isNotSameSize(ramCanvasTpl const & inRC) const {
653 if ((numPixY == inRC.getNumPixY()) && (numPixX == inRC.getNumPixX()))
654 return false;
655 else
656 return true;
657 }
658 //--------------------------------------------------------------------------------------------------------------------------------------------------------
659 /** Return true if corresponding pixels in each canvas are "close" as defined by colorTpl::isClose(). */
660 inline bool isClose(ramCanvasTpl const & inRC, colorChanType epsilon) const {
661 if (isNotSameSize(inRC))
662 return false;
663 for(intCrdT y=0; y<numPixY; y++)
664 for(intCrdT x=0; x<numPixX; x++)
665 if ( !(getPxColorRefNC(x, y).isClose(inRC.getPxColorRefNC(x, y), epsilon)))
666 return false;
667 return true;
668 }
669 //--------------------------------------------------------------------------------------------------------------------------------------------------------
670 /** Return true if corresponding pixels in each canvas are "equal" as defined by colorTpl::isEqual(). */
671 inline bool isEqual(ramCanvasTpl const & inRC) const {
672 if (isNotSameSize(inRC))
673 return false;
674 for(intCrdT y=0; y<numPixY; y++)
675 for(intCrdT x=0; x<numPixX; x++)
676 if ( !(getPxColorRefNC(x, y).isEqual(inRC.getPxColorRefNC(x, y))))
677 return false;
678 return true;
679 }
680 //@}
681
682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
683 /** @name Canvas Rotation and Reflection. */
684 //@{
685 //--------------------------------------------------------------------------------------------------------------------------------------------------------
686 /** Loss-less 90 degree clockwise rotation of the canvas about the center.
687 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
688 "in place", so enough memory is required to duplicate the canvas. */
689 void rotate90CW();
690 //--------------------------------------------------------------------------------------------------------------------------------------------------------
691 /** Loss-less 90 degree counter clockwise rotation of the canvas about the center.
692 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
693 place", so enough memory is required to duplicate the canvas. */
694 void rotate90CCW();
695 //--------------------------------------------------------------------------------------------------------------------------------------------------------
696 /** Loss-less 180 degree rotation of the canvas about the center.
697 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
698 duplicate the canvas. */
699 void rotate180();
700 //--------------------------------------------------------------------------------------------------------------------------------------------------------
701 /** Loss-less, horizontal flip of the canvas about the center.
702 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. */
703 void flipHorz();
704 //--------------------------------------------------------------------------------------------------------------------------------------------------------
705 /** Loss-less, vertical flip of the canvas about the center.
706 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. */
707 void flipVert();
708 //--------------------------------------------------------------------------------------------------------------------------------------------------------
709 /** Loss-less, vertical flip of the canvas about the center.
710 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.
711 The transformation is not done "in place", so enough memory is required to duplicate the canvas. */
712 void flipTranspose();
713 //@}
714
715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
716 /** @name Canvas Scaling. */
717 //@{
718 //--------------------------------------------------------------------------------------------------------------------------------------------------------
719 /** Scale up the image using proximal interpolation.
720 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
721 histograms stay accurate. The algorithm is very fast as it is very simple.
722 @param xfactor The factor to scale up to -- must be a positive integer. */
723 void scaleUpProximal(int xfactor);
724 //--------------------------------------------------------------------------------------------------------------------------------------------------------
725 /** Scale down using only the upper left pixel from each block.
726 This will tend to highlight horizontal and vertical detail and generally sharpen up the image. Much data is lost with this sort of scaling
727 operation.
728 @param xfactor The factor to scale up to -- must be a positive integer. */
729 void scaleDown1pt(int xfactor);
730 //--------------------------------------------------------------------------------------------------------------------------------------------------------
731 /** Scale down using only the pixel with maximum luminosity in each block.
732 Much like scaleDown1pt(), this will sharpen up a scaled image, but it will also tend to brighten up the image as well.
733 @param xfactor The factor to scale up to -- must be a positive integer. */
734 void scaleDownMax(int xfactor);
735 //--------------------------------------------------------------------------------------------------------------------------------------------------------
736 /** Scale down using the mean pixel value from each block.
737 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
738 pixel. This algorithm tends to "fuzz-up" the result -- frequently used for super-sampling.
739 @param xfactor The factor to scale down to -- must be a positive integer. */
740 void scaleDownMean(int xfactor);
741 //@}
742
743 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
744 /** @name Geometric transformations (Reverse Mapping)
745
746 @warning These functions are experimental! Functionality and API are likely to change in the future.
747 */
748 //@{
749 //--------------------------------------------------------------------------------------------------------------------------------------------------------
750 /** Geometric Transform via Radial Polynomial implemented with Reverse Mapping.
751
752 @warning This function is experimental! Functionality and API are likely to change in the future.
753
754 @param RPoly RPoly is a vector listing the coefficients of a univariate polynomial in lexicographical order --
755 i.e. RPoly[0] is the coefficients on the highest power term.
756 @param rScale Scale to apply before the transformation to the *radius*.
757 @param Xo X coordinate for origin translation -- applied before RPoly and reversed after RPoly & scale.
758 @param Yo Y coordinate for origin translation -- applied before RPoly and reversed after RPoly & scale.
759 @param oScale Scale to apply after RPoly and before reverse translation.
760 @param errorColor The color to use for pixels with no valid mapping.
761 @param interpMethod Eventually this will be the interpolation method used. */
762 ramCanvasTpl geomTfrmRevRPoly(std::vector<double> const& RPoly,
763 double rScale,
764 double Xo,
765 double Yo,
766 double oScale,
767 colorArgType errorColor = colorCornerEnum::GREEN,
768 interpolationType interpMethod = interpolationType::BILINEAR);
769 //--------------------------------------------------------------------------------------------------------------------------------------------------------
770 /** Geometric Transform via bivariate polynomial implemented with Reverse Mapping.
771
772 @warning This function is experimental! Functionality and API are likely to change in the future.
773
774 @param BiPolyX Coefficients for a bivariate polynomial in lexicographical order -- used to map x coordinates.
775 @param BiPolyY Coefficients for a bivariate polynomial in lexicographical order -- used to map y coordinates.
776 @param Xo X coordinate for origin translation -- applied before BiPoly*and reversed after BiPoly*& scale.
777 @param Yo Y coordinate for origin translation -- applied before BiPoly*and reversed after BiPoly*& scale.
778 @param oScale Scale to apply after BiPoly*and before reverse translation.
779 @param errorColor The color to use for pixels with no valid mapping.
780 @param interpMethod Eventually this will be the interpolation method used. */
781 ramCanvasTpl geomTfrmRevBiPoly(std::vector<double> const& BiPolyX,
782 std::vector<double> const& BiPolyY,
783 double Xo,
784 double Yo,
785 double oScale,
786 colorArgType errorColor = colorCornerEnum::GREEN,
787 interpolationType interpMethod = interpolationType::BILINEAR);
788 //--------------------------------------------------------------------------------------------------------------------------------------------------------
789 /** Homogenious Affine Geometric Transform implemented with Reverse Mapping.
790
791 @warning This function is experimental! Functionality and API are likely to change in the future.
792
793 @verbatim
794 [1 0 T_x] [S_x 0 0] [cA sA 0] [x_in] [x_out]
795 [0 1 T_y] [0 S_y 0] [-SA cA 0] T * [y_in] => [y_out]
796 [0 0 1 ] [0 0 1] [0 0 1] [1 ] [1 ]
797 @endverbatim
798 @param HAMatrix Homogeneous affine transform matrix -- 9 elements interpreted as a row major order 3x3 matrix.
799 @param Xo X coordinate for origin translation -- applied before HAMatrixand reversed after HAMatrix& scale.
800 @param Yo Y coordinate for origin translation -- applied before HAMatrixand reversed after HAMatrix& scale.
801 @param oScale Scale to apply after HAMatrixand before reverse translation.
802 @param errorColor The color to use for pixels with no valid mapping.
803 @param interpMethod Eventually this will be the interpolation method used. */
804 ramCanvasTpl geomTfrmRevAff(std::vector<double> const& HAMatrix,
805 double Xo,
806 double Yo,
807 double oScale,
808 colorArgType errorColor = colorCornerEnum::GREEN,
809 interpolationType interpMethod = interpolationType::BILINEAR);
810 //--------------------------------------------------------------------------------------------------------------------------------------------------------
811 /** Geometric Transform via provided mapping function implemented with Reverse Mapping.
812
813 @warning This function is experimental! Functionality and API are likely to change in the future.
814
815 @param f The coordinate transformation function
816 @param Xo X coordinate for origin translation -- applied before f and reversed after f & scale.
817 @param Yo Y coordinate for origin translation -- applied before f and reversed after f & scale.
818 @param oScale Scale to apply after f and before reverse translation.
819 @param errorColor The color to use for pixels with no valid mapping.
820 @param interpMethod Eventually this will be the interpolation method used. */
821 ramCanvasTpl geomTfrmRevArb(mjr::point2d<double> (*f)(double, double),
822 double Xo,
823 double Yo,
824 double oScale,
825 colorArgType errorColor = colorCornerEnum::GREEN,
826 interpolationType interpMethod = interpolationType::BILINEAR);
827 //@}
828
829 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
830 /** @name Apply Convolution */
831 //@{
832 //--------------------------------------------------------------------------------------------------------------------------------------------------------
833 /** Apply a convolution filter.
834 The implementation for this method is quite naive and super slow! Frankly, this kind of functionality is beyond the scope of this library; however,
835 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
836 canvas are considered black.
837 @param kernel The convolution kernel. Must be of length kWide*kTall.
838 @param kWide The width of the kernel. Must be odd.
839 @param kTall The height of the kernel. Must be odd.
840 @param divisor Used to normalize dot product at each step. i.e. one might say the kernel for the convolution is really kernel/divisor. */
841 void convolution(double *kernel, int kWide, int kTall, double divisor);
842 void convolution(double *kernel, int kSize, double divisor);
843 void convolution(double *kernel, int kSize);
844 //@}
845
846 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
847 /** @name Compute Convolution Kernels */
848 //@{
849 //--------------------------------------------------------------------------------------------------------------------------------------------------------
850 /** Compute a Gaussian convolution kernel (use with divisor==1.0).
851 @param kernel Pointer to space for the convolution kernel. Must have at least space for kSize*kSize doubles
852 @param kSize The width and height of the kernel. Must be odd.
853 @param sd The standard deviation. */
854 void computeConvolutionMatrixGausian(double *kernel, int kSize, double sd);
855 //--------------------------------------------------------------------------------------------------------------------------------------------------------
856 /** Compute a box blur convolution kernel (use with divisor==1.0).
857 @param kernel Pointer to space for the convolution kernel. Must have at least space for kSize*kSize doubles
858 @param kSize The width and height of the kernel. Must be odd. */
859 void computeConvolutionMatrixBox(double *kernel, int kSize);
860 //@}
861
862 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
863 /** @name Iterators */
864 //@{
865 colorT *begin() { return pixels; }
866 colorT *end() { return pixelsE; }
867 //@}
868
869 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
870 /** @name Functional Homogeneous Pixel Transformations (point operators) */
871 //@{
872 //--------------------------------------------------------------------------------------------------------------------------------------------------------
873 /** Apply a homogeneous pixel transformation.
874 Homogeneous pixel transformations don't vary based upon the coordinates of the pixel in question, but depend only upon the value of the pixel.
875 Thus, a homogeneous pixel transformation can be considered as a pixel function applied to each pixel in an image. Many standard pixel functions are
876 defined within the colorT object. The ramCanvasTpl object must then only apply the methods available within each colorT class to support most of
877 the standard homogeneous pixel transformations. Additionally, new functions are automatically available to the ramCanvasTpl (both in the colorT
878 class and new functions from other sources). */
879 void applyHomoPixTfrm(colorT& (colorT::*HPT)());
880 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double), double);
881 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double, double);
882 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double, double, double);
883 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double), double, double, double, double);
884 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double), double, double, double, double, double);
885 void applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double), double, double, double, double, double, double);
886 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int), int);
887 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int, int);
888 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int, int, int);
889 void applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int, int, int, int);
890 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT), colorT);
891 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT, colorT);
892 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT, colorT, colorT);
893 void applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT, colorT, colorT, colorT);
894 //@}
895
896 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
897 /** @name Predefined Homogeneous Pixel Transformations (point operators) */
898 //@{
899 //--------------------------------------------------------------------------------------------------------------------------------------------------------
900 /** Computes a linear grey level scale homogeneous pixel transformation.
901 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
902 assumed by any pixel color component. This function is sometimes called "auto contrast adjust" or "linear auto contrast adjust". */
903 void autoHistStrech();
904 //--------------------------------------------------------------------------------------------------------------------------------------------------------
905 /** Computes a, possibly different, linear grey level scale homogeneous pixel transformation on each channel of the image.
906 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.
907 i.e. this is the same as applying autoHistStrech independently to each channel.*/
908 void autoMaxHistStrechRGB();
909 //@}
910
911 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
912 /** @name Canvas Combination Functions */
913 //@{
914 //--------------------------------------------------------------------------------------------------------------------------------------------------------
915 /** This function takes a ramCanvasTpl and combines it with the current ramCanvasTpl using the provided binary operator.
916 @param HPT Pointer to a binary operator.
917 @param theCanvas This is the ramCanvasTpl to combine with.
918 @param trgX Final X coordinate for the left of the combined region. Default: 0
919 @param trgY Final Y coordinate for the top of the combined region. Default: 0
920 @param srcX Left edge of the region to combine with. Default: 0
921 @param srcY Top edge of the region to combine with. Default: 0
922 @param wide Width of the region to combine with. Default: -1 (indicates to edge of canvas)
923 @param tall Height of the region to combine with. Default: -1 (indicates to edge of canvas) */
924 void combineRamCanvasBinOp(colorT& (colorT::*HPT)(colorT),
925 const ramCanvasTpl &theCanvas,
926 intCrdT trgX = 0, intCrdT trgY = 0,
927 intCrdT wide = -1, intCrdT tall = -1,
928 intCrdT srcX = 0, intCrdT srcY = 0);
929 //@}
930
931 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
932 /** @name Statistical Canvas Combination Functions (useful for CCD imaging) */
933 //@{
934 //--------------------------------------------------------------------------------------------------------------------------------------------------------
935 /** Take a list of ramCanvasTpl objects and combine them with the current ramCanvasTpl using mean.
936 @param theCanvasList This is the array of ramCanvasTpl's to combine with.
937 @param N The number of canvas objects. */
938 void combineRamCanvasMean(ramCanvasTpl *theCanvasList, const int N);
939 //@}
940
941 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
942 /** @name Canvas Clearing Methods */
943 //@{
944 //--------------------------------------------------------------------------------------------------------------------------------------------------------
945 /** Clear the canvas to black. Faster than clrCanvas(). */
946 void clrCanvasToBlack();
947 //--------------------------------------------------------------------------------------------------------------------------------------------------------
948 /** Clear the canvas to black. Faster than clrCanvas(). */
949 void clrCanvasToWhite();
950 //--------------------------------------------------------------------------------------------------------------------------------------------------------
951 /** Set the given channel to the minimum value. */
952 void clrCanvasChannelToMin(int chan);
953 //--------------------------------------------------------------------------------------------------------------------------------------------------------
954 /** Set the given channel to the maximum value. */
955 void clrCanvasChannelToMax(int chan);
956 //--------------------------------------------------------------------------------------------------------------------------------------------------------
957 /** Clear the canvas. */
958 void clrCanvas();
959 //--------------------------------------------------------------------------------------------------------------------------------------------------------
960 /** @overload */
961 void clrCanvas(colorArgType color);
962 //@}
963
964 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
965 /** @name Default Point Methods */
966 //@{
967 //--------------------------------------------------------------------------------------------------------------------------------------------------------
968 /** Set the current default point to the given coordinates.
969 @param x The x coordinate of the point to move to.
970 @param y The y coordinate of the point to move to. */
971 inline void moveTo(intCrdT x, intCrdT y) { dfltX = x; dfltY = y; }
972 inline void moveTo(fltCrdT x, fltCrdT y) { moveTo(real2intX(x), real2intY(y)); }
973 inline void moveTo(pointIntType thePoint) { moveTo(thePoint.x, thePoint.y); }
974 inline void moveTo(pointFltType thePoint) { moveTo(real2intX(thePoint.x), real2intY(thePoint.y)); }
975 //@}
976
977 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
978 /** @name Default Color Methods */
979 //@{
980 //--------------------------------------------------------------------------------------------------------------------------------------------------------
981 /** Set the default color */
982 inline void setDfltColor(colorArgType color) { dfltColor = color; }
983 inline void setDfltColor(std::string cornerColor) { dfltColor.setToCorner(cornerColor); }
984 inline void setDfltColor(const char* cornerColor) { dfltColor.setToCorner(std::string(cornerColor)); }
985 inline void setDfltColor(colorChanType r, colorChanType g, colorChanType b) { dfltColor.setChansRGB(r, g, b); }
986 //@}
987
988 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
989 /** @name Point drawing functions */
990 //@{
991 //--------------------------------------------------------------------------------------------------------------------------------------------------------
992 /** Draw a point at the specified coordinates with the specified color.
993 Overloaded versions exist with various arguments.
994 @param x The x coordinate of the point
995 @param y The y coordinate of the point
996 @param color The color to draw the point */
997 inline void drawPoint(intCrdT x, intCrdT y, colorArgType color) {
998 if(isOnCanvas(x, y))
999 drawPointNC(x, y, color);
1000 }
1001 inline void drawPoint() { drawPoint(dfltX, dfltY, dfltColor); }
1002 inline void drawPoint(colorArgType color) { drawPoint(dfltX, dfltY, color); }
1003 inline void drawPoint(intCrdT x, intCrdT y) { drawPoint(x, y, dfltColor); }
1004 inline void drawPoint(fltCrdT x, fltCrdT y) { drawPoint(x, y, dfltColor); }
1005 inline void drawPoint(fltCrdT x, fltCrdT y, colorArgType color) { drawPoint(real2intX(x), real2intY(y), color); }
1006 inline void drawPoint(pointIntType thePoint, colorArgType color) { drawPoint(thePoint.x, thePoint.y, color); }
1007 inline void drawPoint(pointIntType thePoint) { drawPoint(thePoint.x, thePoint.y, dfltColor); }
1008 inline void drawPoint(pointFltType thePoint) { drawPoint(real2intX(thePoint.x), real2intY(thePoint.y), dfltColor); }
1009 inline void drawPoint(pointFltType thePoint, colorArgType color) { drawPoint(real2intX(thePoint.x), real2intY(thePoint.y), color); }
1010 //@}
1011
1012 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1013 /** @name Line Drawing Methods */
1014 //@{
1015 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1016 /** Draw a line.
1017 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
1018 current canvas.
1019 @param x1 x coordinate of the first point
1020 @param y1 y coordinate of the first point
1021 @param x2 x coordinate of the second point
1022 @param y2 y coordinate of the second point
1023 @param color The color to use
1024
1025 @par Performance Note
1026 This function will perform better if (x1,y2) and (x2,y2) are in the clip region. Further x1<x2 will save several steps in
1027 the algorithm.
1028
1029 @par Algorithm Notes
1030 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
1031 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
1032 for positive slope lines and for negative slope lines.
1033
1034 The algorithms used to draw lines in the last four cases are related to the classic algorithm presented by Bresenham in 1965 and the
1035 extensions to Bresenham's algorithm given by Pitteway in 1967 and Van Aken in 1984. The basic algorithm described by Bresenham, Pitteway, and Van
1036 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
1037 obvious extensions to the midpoint algorithm. Each case is customized and optimized for the given slope class.
1038
1039 The clipping algorithm used for the last slope classes is similar in spirit to the Cohen-Sutherland Line-Clipping algorithm, but is optimized
1040 for each slope class. Several pre-checks are made in order to avoid the slope computations in the Cohen-Sutherland algorithm -- in fact intersections
1041 are only computed if absolutely required. Note that the only floating point computations in this function are the intersection computations, and they
1042 will be avoided completely if the given line need not be clipped.*/
1043 void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1044 inline void drawLine(pointFltType point1) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), dfltColor); }
1045 inline void drawLine(pointFltType point1, colorArgType color) { drawLine( dfltX, dfltY, real2intX(point1.x), real2intY(point1.y), color); }
1046 inline void drawLine(pointIntType point1) { drawLine( dfltX, dfltY, point1.x, point1.y, dfltColor); }
1047 inline void drawLine(pointIntType point1, colorArgType color) { drawLine( dfltX, dfltY, point1.x, point1.y, color); }
1048 inline void drawLine(pointFltType point1, pointFltType point2) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1049 inline void drawLine(pointFltType point1, pointFltType point2, colorArgType color) { drawLine(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1050 inline void drawLine(pointIntType point1, pointIntType point2) { drawLine( point1.x, point1.y, point2.x, point2.y, dfltColor); }
1051 inline void drawLine(pointIntType point1, pointIntType point2, colorArgType color) { drawLine( point1.x, point1.y, point2.x, point2.y, color); }
1052 inline void drawLine(intCrdT x, intCrdT y) { drawLine( dfltX, dfltY, x, y, dfltColor); }
1053 inline void drawLine(fltCrdT x, fltCrdT y) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), dfltColor); }
1054 inline void drawLine(intCrdT x, intCrdT y, colorArgType color) { drawLine( dfltX, dfltY, x, y, color); }
1055 inline void drawLine(fltCrdT x, fltCrdT y, colorArgType color) { drawLine( dfltX, dfltY, real2intX(x), real2intY(y), color); }
1056 inline void drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
1057 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawLine( x1, y1, x2, y2, dfltColor); }
1058 inline void drawLine(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawLine( real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1059 //@}
1060
1061 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1062 /** @name Unfilled Triangle Drawing Methods */
1063 //@{
1064 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1065 /** Draw an un-filled triangle
1066 @bug Some pixels may be drawn more than once.
1067 @param x1 The x coordinate of the first point
1068 @param y1 The y coordinate of the first point
1069 @param x2 The x coordinate of the second point
1070 @param y2 The y coordinate of the second point
1071 @param x3 The x coordinate of the third point
1072 @param y3 The y coordinate of the third point
1073 @param color The color to use for the triangle */
1074 void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1075 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); }
1076 inline void drawTriangle(pointFltType *thePoints) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1077 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1078 real2intX(thePoints[2].x), real2intY(thePoints[2].y), dfltColor); }
1079 inline void drawTriangle(pointFltType *thePoints, colorArgType color) { drawTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1080 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1081 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1082 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); }
1083 inline void drawTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1084 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1085 real2intX(point2.x), real2intY(point2.y),
1086 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1087 inline void drawTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawTriangle(real2intX(point1.x), real2intY(point1.y),
1088 real2intX(point2.x), real2intY(point2.y),
1089 real2intX(point3.x), real2intY(point3.y), color); }
1090 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); }
1091 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); }
1092 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); }
1093 inline void drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1094 //@}
1095
1096 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1097 /** @name Filled Triangle Drawing Methods */
1098 //@{
1099 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1100 /** Draw a triangle filled with a solid color using a nicely optimized, horizontal scan conversion algorithm.
1101 @bug Triangles not entirely on the canvas are not rendered.
1102 @bug Not thread safe.
1103 @param x1 The x coordinate of the first point
1104 @param y1 The y coordinate of the first point
1105 @param x2 The x coordinate of the second point
1106 @param y2 The y coordinate of the second point
1107 @param x3 The x coordinate of the third point
1108 @param y3 The y coordinate of the third point
1109 @param color The color to use for the triangle */
1110 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color);
1111 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); }
1112 inline void drawFillTriangle(pointFltType *thePoints) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1113 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1114 real2intX(thePoints[2].x), real2intY(thePoints[2].y), dfltColor); }
1115 inline void drawFillTriangle(pointFltType *thePoints, colorArgType color) { drawFillTriangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y),
1116 real2intX(thePoints[1].x), real2intY(thePoints[1].y),
1117 real2intX(thePoints[2].x), real2intY(thePoints[2].y), color); }
1118 inline void drawFillTriangle(pointIntType *thePoints) { drawFillTriangle(thePoints[0].x, thePoints[0].y,
1119 thePoints[1].x, thePoints[1].y,
1120 thePoints[2].x, thePoints[2].y, dfltColor); }
1121 inline void drawFillTriangle(pointIntType point1, pointIntType point2, pointIntType point3) { drawFillTriangle(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, dfltColor); }
1122 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1123 real2intX(point2.x), real2intY(point2.y),
1124 real2intX(point3.x), real2intY(point3.y), dfltColor); }
1125 inline void drawFillTriangle(pointFltType point1, pointFltType point2, pointFltType point3, colorArgType color) { drawFillTriangle(real2intX(point1.x), real2intY(point1.y),
1126 real2intX(point2.x), real2intY(point2.y),
1127 real2intX(point3.x), real2intY(point3.y), color); }
1128 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); }
1129 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); }
1130 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); }
1131 inline void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3) { drawFillTriangle(x1, y1, x2, y2, x3, y3, dfltColor); }
1132 //@}
1133
1134 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1135 /** @name Shaded Triangle Drawing Methods */
1136 //@{
1137 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1138 /** Draw a filled triangle using barycentric color interpolation.
1139 @bug Triangles not entirely on the canvas are not rendered.
1140 @bug Degenerate trainagles are not rendered
1141 @bug Painfully slow
1142 @param x1 The x coordinate of the first point
1143 @param y1 The y coordinate of the first point
1144 @param x2 The x coordinate of the second point
1145 @param y2 The y coordinate of the second point
1146 @param x3 The x coordinate of the third point
1147 @param y3 The y coordinate of the third point
1148 @param color1 The color of the first point (x1, y1)
1149 @param color2 The color of the second point (x2, y2)
1150 @param color3 The color of the third point (x3, y3) */
1151 void drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color1, colorArgType color2, colorArgType color3);
1152 //@}
1153
1154 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1155 /** @name Unfilled Rectangle Drawing Functions */
1156 //@{
1157 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1158 /** Draw an unfilled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1159 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
1160 the bounds of the canvas using the specified color.
1161 @param x1 The x coordinate of first corner
1162 @param y1 The y coordinate of first corner
1163 @param x2 The x coordinate of second corner
1164 @param y2 The y coordinate of second corner
1165 @param color The color to use */
1166 void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1167 inline void drawRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1168 inline void drawRectangle(pointIntType point1, pointIntType point2) { drawRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1169 inline void drawRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1170 inline void drawRectangle(pointFltType point1, pointFltType point2) { drawRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1171 inline void drawRectangle(pointIntType *thePoints, colorArgType color) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1172 inline void drawRectangle(pointFltType *thePoints) { drawRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1173 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); }
1174 inline void drawRectangle(pointIntType *thePoints) { drawRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1175 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1176 inline void drawRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1177 inline void drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawRectangle(x1, y1, x2, y2, dfltColor); }
1178 //@}
1179
1180 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1181 /** @name Filled Rectangle Drawing Methods */
1182 //@{
1183 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1184 /** Draw a filled rectangle with diagonal corners located at (x1, y1) and and (x2, y2).
1185 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
1186 the bounds of the canvas using the specified color.
1187 @param x1 The x coordinate of first corner
1188 @param y1 The y coordinate of first corner
1189 @param x2 The x coordinate of second corner
1190 @param y2 The y coordinate of second corner
1191 @param color The color to use */
1192 void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color);
1193 inline void drawFillRectangle(pointIntType point1, pointIntType point2, colorArgType color) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, color); }
1194 inline void drawFillRectangle(pointIntType point1, pointIntType point2) { drawFillRectangle(point1.x, point1.y, point2.x, point2.y, dfltColor); }
1195 inline void drawFillRectangle(pointFltType point1, pointFltType point2, colorArgType color) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), color); }
1196 inline void drawFillRectangle(pointFltType point1, pointFltType point2) { drawFillRectangle(real2intX(point1.x), real2intY(point1.y), real2intX(point2.x), real2intY(point2.y), dfltColor); }
1197 inline void drawFillRectangle(pointIntType *thePoints, colorArgType color) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, color); }
1198 inline void drawFillRectangle(pointFltType *thePoints) { drawFillRectangle(real2intX(thePoints[0].x), real2intY(thePoints[0].y), real2intX(thePoints[1].x), real2intY(thePoints[1].y), dfltColor); }
1199 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); }
1200 inline void drawFillRectangle(pointIntType *thePoints) { drawFillRectangle(thePoints[0].x, thePoints[0].y, thePoints[1].x, thePoints[1].y, dfltColor); }
1201 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), dfltColor); }
1202 inline void drawFillRectangle(fltCrdT x1, fltCrdT y1, fltCrdT x2, fltCrdT y2, colorArgType color) { drawFillRectangle(real2intX(x1), real2intY(y1), real2intX(x2), real2intY(y2), color); }
1203 inline void drawFillRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) { drawFillRectangle(x1, y1, x2, y2, dfltColor); }
1204 //@}
1205
1206 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1207 /** @name Unfilled Circle Drawing Methods */
1208 //@{
1209 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1210 /** Draw an un-filled circle.
1211 The algorithm used is based upon the one presented in "A Linear Algorithm for Incremental Digital Display of Circular Arcs" published in the
1212 Communications of the AMC in Feb 1977 and written by J.E. Bresenham. Bresenham's algorithm has been significantly improved by using only integer
1213 arithmetic and adding second order differences to the computation -- much the way the line drawing algorithm works in this package. The algorithm
1214 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
1215 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.
1216 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
1217 optimized.
1218 @bug Draws everyting even if it's off the canvas.
1219 @param centerX The x coordinate of the center
1220 @param centerY The y coordinate of the center
1221 @param radiusX The radius of the circle
1222 @param color The color to draw the circle with */
1223 void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1224 inline void drawCircle(intCrdT radiusX) { drawCircle(dfltX, dfltY, radiusX, dfltColor); }
1225 inline void drawCircle(fltCrdT radiusX) { drawCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1226 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1227 inline void drawCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1228 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX) { drawCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1229 inline void drawCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1230 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1231 inline void drawCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1232 inline void drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawCircle(centerX, centerY, radiusX, dfltColor); }
1233 //@}
1234
1235 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1236 /** @name Filled Circle Drawing Methods */
1237 //@{
1238 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1239 /** Draw an un-filled circle.
1240 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
1241 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
1242 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
1243 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
1244 X axis -- i.e. the radius of the drawn circle will be measured horizontally. This function is well optimized.
1245 @bug Draws everyting even if it's off the canvas.
1246 @param centerX The x coordinate of the center
1247 @param centerY The y coordinate of the center
1248 @param radiusX The radius of the circle
1249 @param color The color to draw the circle with */
1250 void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color);
1251 inline void drawFillCircle(fltCrdT radiusX) { drawFillCircle(dfltX, dfltY, realDelta2intX(radiusX), dfltColor); }
1252 inline void drawFillCircle(intCrdT radiusX) { drawFillCircle(dfltX, dfltY, radiusX, dfltColor); }
1253 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), color); }
1254 inline void drawFillCircle(pointFltType centerPoint, fltCrdT radiusX) { drawFillCircle(real2intX(centerPoint.x), real2intY(centerPoint.y), realDelta2intX(radiusX), dfltColor); }
1255 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX, colorArgType color) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, color); }
1256 inline void drawFillCircle(pointIntType centerPoint, intCrdT radiusX) { drawFillCircle(centerPoint.x, centerPoint.y, radiusX, dfltColor); }
1257 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), dfltColor); }
1258 inline void drawFillCircle(fltCrdT centerX, fltCrdT centerY, fltCrdT radiusX, colorArgType color) { drawFillCircle(real2intX(centerX), real2intY(centerY), realDelta2intX(radiusX), color); }
1259 inline void drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX) { drawFillCircle(centerX, centerY, radiusX, dfltColor); }
1260 //@}
1261
1262 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1263 /** @name Piece-Wise Linear Curve Drawing Methods */
1264 //@{
1265 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1266 /** Draw Piece-Wise Linear Curves
1267 @bug Some pixels may be drawn more than once.
1268 */
1269 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y, colorArgType color);
1270 void drawPLCurve(int numPoints, intCrdT *x, intCrdT *y);
1271 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y, colorArgType color);
1272 void drawPLCurve(int numPoints, fltCrdT *x, fltCrdT *y);
1273 void drawPLCurve(int numPoints, pointIntType *thePoints, colorArgType color);
1274 void drawPLCurve(int numPoints, pointIntType *thePoints);
1275 void drawPLCurve(int numPoints, pointFltType *thePoints, colorArgType color);
1276 void drawPLCurve(int numPoints, pointFltType *thePoints);
1277 //@}
1278
1279 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1280 /** @name Hershey Glyph Rendering Utility Functions */
1281 //@{
1282 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1283 /** Render a glyph from the Hershey character set.
1284 The glyph is rendered with its origin at the given coordinates. This function is intended to provide only the most basic glyph rendering. For
1285 example, glyphs are rendered with the line drawing functions, and therefore are not anti-aliased.
1286 @param glyphNum The character number of the glyph to render
1287 @param x The x coordinate at which to render the glyph
1288 @param y The x coordinate at which to render the glyph
1289 @param magX The magnification of the glyph in the x direction
1290 @param magY The magnification of the glyph in the y direction
1291 @param aColor The color with which to render the glyph */
1292 void drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor);
1293 void drawHersheyGlyph(int glyphNum, fltCrdT x, fltCrdT y, double magX, double magY, colorArgType aColor) { drawHersheyGlyph(glyphNum, real2intX(x), real2intY(y), magX, magY, aColor); }
1294 //@}
1295
1296 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1297 /** @name ASCII Character Rendering.
1298 What are font rendering functions doing in a raster graphics library? Sometimes I like to put a label on image.*/
1299 //@{
1300 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1301 /** Render a string using Hershey ASCII Fonts.
1302 While the string is rendered with fixed font spacing, the Hershey fonts are not fixed width fonts.
1303 @param aString The string
1304 @param aFont The font to set the default with
1305 @param x The x coordinate at which to render the first glyph
1306 @param y The x coordinate at which to render the first glyph
1307 @param aColor The color with which to render the glyphs
1308 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1309 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1310 void drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc);
1311 void drawString(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType aColor, double cex, intCrdT spc) {
1312 drawString(aString, aFont, real2intX(x), real2intY(y), aColor, cex, spc);
1313 }
1314 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1315 /** Renders a filled, bounding box for the given string as rendered via drawString.
1316 @param aString A string to render
1317 @param aFont The font to set the default with
1318 @param x The x coordinate at which to render the first glyph
1319 @param y The x coordinate at which to render the first glyph
1320 @param stringColor The color with which to render the glyphs
1321 @param boxColor The color with which to render the BOX
1322 @param cex A factor by which to expand the size of each glyph -- 1 is a good value (the name comes from R).
1323 @param spc Space to jump for each charcter -- 20 for SL fonts, 23 for DL fonts, and 25 for TL fonts. Scaled with cex. */
1324 void drawStringBox(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc);
1325 void drawStringBox(std::string aString, mjr::hershey::font aFont, fltCrdT x, fltCrdT y, colorArgType stringColor, colorArgType boxColor, double cex, intCrdT spc) {
1326 drawStringBox(aString, aFont, real2intX(x), real2intY(y), stringColor, boxColor, cex, spc);
1327 }
1328 //@}
1329
1330 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1331 /** @name File Reading and Writing Methods */
1332 //@{
1333 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1334 /** Is libTIFF supported -- that is: will the readTIFFfile() method do anything?
1335 Note that readTIFFfile() is the only method that needs libTIFF. In particular, writeTIFFfile() works without libTIFF. */
1336 bool supportLibTIFF();
1337 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1338 /** If the libTIFF library was found at build time, this function will read a TIFF file into current ramCanvas object.
1339
1340 If libTIFF is not supported, then this function returns 32. You can test if this method works via the supportLibTIFF() method.
1341
1342 Notable features:
1343 - Arbitrary TIFF image file types are converted to 24-bit RGB when aRamCanvas is of type ramCanvas3c8b
1344 - Note aRamCanvas must be of type ramCanvas3c8b -- ramCanvas4c8b is not good enough.
1345 - Reasonable conversions are made in other cases.
1346 - if aRamCanvas has fewer channels than the TIFF file, then extra channels in the TIFF file are ignored
1347 - if aRamCanvas has more channels than the TIFF file, then extra channels of aRamCanvas are set to black
1348 - 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)
1349 - Some effort is taken to do the right thing with respect to aRamCanvas axis orientation
1350
1351 @param fileName The file name from which to read data from.
1352 @retval 0 Image file loaded successfully
1353 @retval 1 File open (TIFFOpen) failure
1354 @retval 2 File missing TIFF tag: IMAGEWIDTH
1355 @retval 3 File missing TIFF tag: IMAGELENGTH
1356 @retval 4 File missing TIFF tag: SAMPLESPERPIXEL
1357 @retval 5 File missing TIFF tag: PLANARCONFIG
1358 @retval 6 File missing TIFF tag: PHOTOMETRIC
1359 @retval 7 File missing TIFF tag: BITSPERSAMPLE
1360 @retval 8 File of zero width
1361 @retval 9 File of zero height
1362 @retval 10 Allocation failed (temp image buffer)
1363 @retval 11 Read (TIFFReadRGBAImage) failure
1364 @retval 12 Canvas Allocation failed (insufficient width)
1365 @retval 14 Canvas Allocation failed (insufficient height)
1366 @retval 15 TIFF bps not 8, 16, 32, or 64
1367 @retval 16 Allocation failed (scan line buffer)
1368 @retval 17 Read (TIFFReadScanline) failure
1369 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1370 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1371 @retval 20 File and ramCanvas channel depth differ
1372 @retval 21 File and ramCanvas channel format (int vs float) differ
1373 @retval 22 Planar configuration is invalid (not 1 or 2)
1374 @retval 23 Tiled images are not supported
1375 @retval 24 PHOTOMETRIC_PALETTE not supported
1376 @retval 32 TIFF read support not provided in this compile */
1377 int readTIFFfile(std::string fileName);
1378 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1379 /** Write a TIFF format image file. Respects integer coordinate system orientation.
1380
1381 Why TIFF? TIFF is both broadly supported and flexible enough to represent almost every ramCanvas image type perfectly.
1382
1383 Use Cases (In order of priority)
1384 - Write a bit perfect TIFF representation of ramCanvas images
1385 - Simultaneously convert any ramCanvas into 24-bit truecolor RGB and write the resulting TIFF
1386 - Do all the above while simultaneously applying a homogeneous image filter
1387
1388 Limitations
1389 - Channels must be no more than 64-bits wide
1390 - No more than 2^16-1 channels
1391 - Image width no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1392 - Image height no more than 2^32-1 (normally intCrdT limits this to 2^31-1)
1393 - Image row data size (numPixX * colorT::bitsPerChan * colorT::channelCount / 8) must be less than 2^32-1 bytes
1394 - Image data must be less than 2^32-1 bytes
1395
1396 Limitations for bit perfect (toTRU is NULL) files:
1397 - Channels must be uint8_t, uint16_t, uint32_t, uint64_t, float (32-bit), or double (64-bit)
1398
1399 @param fileName The file name to write data to
1400 @param rcConverter An rcConverter object instance
1401 @param markAlpha If an alpha channel is present, then mark it as such in the TIFF file.
1402 @return Status of I/O
1403 @retval 0 Everything seems to have worked
1404 @retval 2 Image channels are too shallow for TIFF format
1405 @retval 3 Image channels are too deep for TIFF format
1406 @retval 4 Image has too few channels for TIFF format
1407 @retval 5 Image has too many channels for TIFF format
1408 @retval 6 Image has too few columns for TIFF format
1409 @retval 7 Image has too many columns for TIFF format
1410 @retval 8 Image has too few rows for TIFF format
1411 @retval 9 Image has too few rows for TIFF format
1412 @retval 10 Image rows are too large (too much data) for TIFF format
1413 @retval 11 Image is too large (too much data) for TIFF format */
1414 template <class rcConT> int writeTIFFfile(std::string fileName, rcConT rcConverter, bool markAlpha);
1415 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1416 /** Simplified overload for writeTIFFfile() that only requires the filename. */
1417 int writeTIFFfile(std::string fileName, bool markAlpha = true);
1418 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1419 /** Write a 24-bit (8-bit per channel) RGB, TGA format graphics file. Respects integer coordinate system orientation.
1420
1421 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
1422 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
1423 function to dump out regular RGB images, but I suggest writeTIFFfile() for that.
1424
1425 Note TGA files are 8-bit files, and *_byte functions are used to convert channel values to 8-bit before being written.
1426
1427 @param fileName The file name name to write data to
1428 @return Status of I/O
1429 @retval 0 Everything seems to have worked
1430 @retval 1 File open failure
1431 @retval 6 Image of zero width
1432 @retval 7 Image too wide for TGA format (> 2^16-1)
1433 @retval 8 Image of zero height
1434 @retval 9 Image too tall for TGA format (> 2^16-1) */
1435 int writeTGAfile(std::string fileName);
1436 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1437 /** Read RAW file
1438
1439 @warning This function is experimental! Functionality and API are likely to change in the future.
1440
1441 @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
1442 good fix looks like
1443
1444 @retval 0 Image file loaded successfully
1445 @retval 1 File open failure
1446 @retval 2 NOT USED
1447 @retval 3 NOT USED
1448 @retval 4 NOT USED
1449 @retval 5 NOT USED
1450 @retval 6 NOT USED
1451 @retval 7 NOT USED
1452 @retval 8 File of zero width
1453 @retval 9 File of zero height
1454 @retval 10 NOT USED
1455 @retval 11 Read failure
1456 @retval 12 Canvas Allocation failed (insufficient width)
1457 @retval 14 Canvas Allocation failed (insufficient height)
1458 @retval 15 bps not 8, 16, 32, or 64
1459 @retval 16 NOT USED
1460 @retval 17 NOT USED
1461 @retval 18 Sample Format is not unsigned integer or IEEE floating point
1462 @retval 19 File and ramCanvas samples per pixel (channel count) differs
1463 @retval 20 File and ramCanvas channel depth differ
1464 @retval 21 File and ramCanvas channel format (int vs float) differ
1465 @retval 22 NOT USED
1466 @retval 23 File is signed integer or unsigned float
1467 @retval 24 File is missing MJRRAW magic number
1468 @retval 25 Image data read failure (file may have ended prematurely)
1469 @retval 26 Malformed header
1470 @retval 27 Image is too wide to be supported by ramCanvas
1471 @retval 28 Image is too tall to be supported by ramCanvas
1472 @retval 29 Error reading numbers in header
1473 @retval 32 NOT USED
1474 @retval 33 Image width missing from header
1475 @retval 34 Image height missing from header
1476 @retval 35 Image channel count missing from header
1477 @retval 36 Image channel depth missing from header */
1478 int readRAWfile(std::string fileName);
1479 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1480 /** Write a MJRRAW file. Respects integer coordinate system orientation.
1481
1482 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
1483 data visualization tools -- usually via a feature referred to as a raw importer. ImageMagick, VisIT, ParaView, and ImageJ all can read this type of
1484 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,
1485 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
1486 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.
1487 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
1488 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
1489 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:
1490 x, y, c, b, s, t, & i. The header is followed by the binary image.
1491
1492 Labels:
1493 - x: Number of pixels on X (horizontal axis) expressed as a zero padded, decimal integer
1494 - y: Number of pixels on Y (vertical axis) expressed as a zero padded, decimal integer
1495 - c: Number of channels expressed as a zero padded, decimal integer
1496 - b: Number of bits per channel expressed as a zero padded, decimal integer
1497 - s: Channel signdness (ignored for floating point channels)
1498 - UNS: Unsigned data. DEFAULT VALUE.
1499 - SGN: Signed data
1500 - t: Channel type
1501 - INT: Integral channels. DEFAULT VALUE.
1502 - FLT: Floating point channels
1503 - i: endianness
1504 - BIG: Big endian
1505 - LTL: Little endian
1506 - UNK: Unknown. DEFAULT VALUE. For read we assume file matches system running the code.
1507 - Currently reserved, but unused labels
1508 - p: Pixel format
1509 - MXL: Each pixel of the image is written in sequence. DEFAULT VALUE.
1510 - PLN: Each channel of the *image* is written in sequence.
1511 - BIT: For bit-masks with 8 bits packed in a byte.
1512 - z: Compression
1513 - 000: No compression. DEFAULT VALUE.
1514 - ZLB: Zlib.
1515 - GZP: Gzip.
1516
1517 Two headers that both specify a 256x128 image with 3 unsigned 8-bit integer channels encoded little endian:
1518
1519 MJRRAW
1520 256x128y3c8bUNSsINTtLTLi00000000000000000000000000000000000000000000000000000000000000000000
1521
1522 MJRRAW
1523 0000000000000000256x0000000000000000128y000000000000000000000000003c00000000008bSGNsINTtLTLi
1524
1525 @param fileName The file name name to write data to
1526 @param rcConverter An rcConverter object instance
1527 @retval 0 The write was successful.
1528 @retval 1 Could not open file. */
1529 template <class rcConT> int writeRAWfile(std::string fileName, rcConT rcConverter);
1530 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1531 /** Simplified overload for writeRAWfile() that only requires the filename. */
1532 int writeRAWfile(std::string fileName);
1533 //@}
1534
1535 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1536 /** @name Boolean Clip Test Methods */
1537 //@{
1538 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1539 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1540 @param x The x coordinate of the point to test
1541 @param y The y coordinate of the point to test
1542 @return Returns true if the point would be clipped. */
1543 inline int isCliped(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1544 inline int isCliped(intCrdT x, intCrdT y) const { return ((x < 0) || (y < 0) || (x >= numPixX) || (y >= numPixY)); }
1545 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1546 /** Determine if the given point is within the bounds of the ramCanvasTpl.
1547 @param x The x coordinate of the point to test
1548 @param y The y coordinate of the point to test
1549 @return Returns true if the point would be not be clipped. */
1550 inline int isOnCanvas(fltCrdT x, fltCrdT y) const { return isCliped(real2intX(x), real2intY(y)); }
1551 inline int isOnCanvas(intCrdT x, intCrdT y) const { return ((x >= 0) && (y >= 0) && (x < numPixX) && (y < numPixY)); }
1552 //@}
1553
1554 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1555 /** @name Coordinate Conversions. */
1556 //@{
1557 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1558 /** Convert real x coordinate to integral x coordinate
1559 @param x The real x coordinate value to be converted.
1560 @return The integer x coordinate corresponding to the given x coordinate */
1561 intCrdT real2intX(fltCrdT x) const;
1562 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1563 /** Convert real y coordinate to integral y coordinate
1564 @param y The real y coordinate value to be converted.
1565 @return The integer y coordinate corresponding to the given y coordinate */
1566 intCrdT real2intY(fltCrdT y) const;
1567 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1568 /** Convert integral x coordinate to real x coordinate
1569 @param x The integer x coordinate value to be converted.
1570 @return The real x coordinate corresponding to the given x coordinate */
1571 fltCrdT int2realX(intCrdT x);
1572 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1573 /** Convert integral y coordinate to real y coordinate
1574 @param y The integer y coordinate value to be converted.
1575 @return The real y coordinate corresponding to the given y coordinate */
1576 fltCrdT int2realY(intCrdT y);
1577 //@}
1578
1579 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1580 /** @name Coordinate Pair Conversions. */
1581 //@{
1582 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1583 /** Convert real x & y coordinates to integer x & y coordinates
1584 @param x The integer x coordinate value to be converted.
1585 @param y The integer y coordinate value to be converted.
1586 @return The real x & y coordinates corresponding to the given integer x & y coordinates */
1587 inline pointFltType int2real(intCrdT x, intCrdT y) { return point2d(int2realX(x), int2realY(y)); }
1588 /** Convert integer x & y coordinates to real x & y coordinates
1589 @param x The real x coordinate value to be converted.
1590 @param y The real y coordinate value to be converted.
1591 @return The integer x & y coordinates corresponding to the given real x & y coordinates */
1592 inline pointIntType real2int(intCrdT x, intCrdT y) { return point2d(real2intX(x), real2intY(y)); }
1593 //@}
1594
1595 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1596 /** @name Pixel Corner Coordinates.
1597 */
1598 //@{
1599 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1600 /** Given integer x coordinate, produce real x coordinate for one of the pixel's edge.
1601 @param x The integer x coordinate value to be converted.
1602 @param side The integer x coordinate of the corner -- should be 0 (lower) or 1 (upper).
1603 @return The real x & y coordinates corresponding to the requested corner */
1604 inline fltCrdT int2realSideX(intCrdT x, int side) { return int2realX(x)+pixWidX/(side ? static_cast<fltCrdT>(2.0) : static_cast<fltCrdT>(-2.0)); }
1605 /** Given integer y coordinate, produce real y coordinate for one of the pixel's edge.
1606 @param y The integer y coordinate value to be converted.
1607 @param side The integer y coordinate of the corner -- should be 0 (lower) or 1 (upper).
1608 @return The real y coordinates corresponding to the requested side */
1609 inline fltCrdT int2realSideY(intCrdT y, int side) { return int2realY(y)+pixWidY/(side ? static_cast<fltCrdT>(2.0) : static_cast<fltCrdT>(-2.0)); }
1610 /** Given integer x & y coordinates, produce real x & y coordinates for one of the pixel's corners.
1611 @param x The integer x coordinate value to be converted.
1612 @param y The integer y coordinate value to be converted.
1613 @param sideX The integer x coordinate of the corner -- should be 0 (lower) or 1 (upper).
1614 @param sideY The integer y coordinate of the corner -- should be 0 (lower) or 1 (upper).
1615 @return The real x & y coordinates corresponding to the requested corner */
1616 inline pointFltType int2realCorner(intCrdT x, intCrdT y, int sideX, int sideY) {return point2d(int2realSideX(x, sideX), int2realSideY(y, sideY)); }
1617 /** Given integer x & y coordinates and a corner index, produce real x & y coordinates for one of the pixel's corners.
1618 @param x The integer x coordinate value to be converted.
1619 @param y The integer y coordinate value to be converted.
1620 @param cornerIndex Corner index. 0 => (0, 0); 1 => (0, 1); 2 => (1, 0); 3 => (1, 1);
1621 @return The real x & y coordinates corresponding to the requested corner */
1622 inline pointFltType int2realCorner(intCrdT x, intCrdT y, int cornerIndex) { return int2realCorner(x, y, (cornerIndex >> 1), (cornerIndex & 1)); }
1623 //@}
1624
1625 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1626 /** @name Coordinate Delta Conversions. */
1627 //@{
1628 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1629 /** Convert real distance on the x coordinate axis to an integral distance
1630 @param x The real delta x to be converted
1631 @return integer delta x */
1632 inline intCrdT realDelta2intX(fltCrdT x) const { return static_cast<intCrdT>(static_cast<fltCrdT>(x)/pixWidX); }
1633 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1634 /** Convert real distance on the y coordinate axis to an integral distance
1635 @param y The real delta y to be converted
1636 @return integer delta y */
1637 inline intCrdT realDelta2intY(fltCrdT y) const { return static_cast<intCrdT>(static_cast<fltCrdT>(y)/pixWidY); }
1638 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1639 /** Convert integral distance on the x coordinate to a real distance
1640 @param x The real x coordinate value to be converted.
1641 @return The integer x coordinate corresponding to the given x coordinate */
1642 inline fltCrdT intDelta2realX(intCrdT x) const { return static_cast<fltCrdT>(x)*pixWidX; }
1643 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1644 /** Convert integral distance on the y coordinate to a real distance
1645 @param y real y coordinate value to be converted.
1646 @return The integer y coordinate corresponding to the given y coordinate */
1647 inline fltCrdT intDelta2realY(intCrdT y) const { return static_cast<fltCrdT>(y)*pixWidY; }
1648 //@}
1649
1650 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1651 /** @name Orientation of Real Coordinate Systems */
1652 //@{
1653 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1654 /** Get the real X axis orientation
1655 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1656 inline realAxisOrientation getRealAxOrientationX() { return realAxOrientationX; }
1657 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1658 /** Set the real X axis orientation
1659 @param orientation The orientation (INVERTED or NATURAL)*/
1660 inline void setRealAxOrientationX(realAxisOrientation orientation) { realAxOrientationX = orientation; }
1661 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1662 /** Get the real Y axis orientation
1663 @return INVERTED means inverted with respect to the integer axis, and NATURAL otherwise. */
1664 inline realAxisOrientation getRealAxOrientationY() { return realAxOrientationX; }
1665 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1666 /** Set the real Y axis orientation
1667 @param orientation The orientation (INVERTED or NATURAL) */
1668 inline void setRealAxOrientationY(realAxisOrientation orientation) { realAxOrientationY = orientation; }
1669 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1670 /** Set the real axis orientation to default (NATURAL for both X and Y axes) */
1671 inline void setRealAxisDefaultOrientation() { setRealAxOrientationX(realAxisOrientation::NATURAL); setRealAxOrientationY(realAxisOrientation::NATURAL); }
1672 //@}
1673
1674 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1675 /** @name Drawing Mode */
1676 //@{
1677 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1678 /** Get the current drawing mode.
1679 @return The drawing mode */
1680 inline drawModeType getDrawMode() { return drawMode; }
1681 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1682 /** Set the current drawing mode
1683 NOOP if enableDrawModes is false.
1684 @param newDrawMode The drawing mode */
1685 inline void setDrawMode(drawModeType newDrawMode) { if constexpr (enableDrawModes) drawMode = newDrawMode; }
1686 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1687 /** Set the default draw mode */
1688 inline void setDefaultDrawMode() { setDrawMode(drawModeType::SET); }
1689 //@}
1690
1691 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1692 /** @name Orientation of Integer Coordinate Systems */
1693 //@{
1694 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1695 /** Get the integer X axis orientation
1696 @return NATURAL means increasing to the right. */
1697 inline intAxisOrientation getIntAxOrientationX() { return intAxOrientationX; }
1698 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1699 /** Is the integer X axis NATURAL?
1700 @return true means increasing to the right. */
1701 inline bool isIntAxOrientationNaturalX() { return (intAxOrientationX == intAxisOrientation::NATURAL); }
1702 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1703 /** Set the integer X axis orientation
1704 @param orientation The orientation (INVERTED or NATURAL) */
1705 inline void setIntAxOrientationX(intAxisOrientation orientation) { intAxOrientationX = orientation; }
1706 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1707 /** Get the integer Y axis orientation
1708 @return NATURAL means increasing in the upward direction. */
1709 inline bool isIntAxOrientationNaturalY() { return (intAxOrientationY == intAxisOrientation::NATURAL); }
1710 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1711 /** Is the integer Y axis orientation NATURAL?
1712 @return NATURAL means increasing in the upward direction. */
1713 inline intAxisOrientation getIntAxOrientationY() { return intAxOrientationY; }
1714 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1715 /** Set the integer Y axis orientation
1716 @param orientation The orientation (INVERTED or NATURAL) */
1717 inline void setIntAxOrientationY(intAxisOrientation orientation) { intAxOrientationY = orientation; }
1718 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1719 /** Set the integer axis orientation to default (NATURAL for both X and Y axes) */
1720 inline void setIntAxisDefaultOrientation() { setIntAxOrientationX(intAxisOrientation::NATURAL); setIntAxOrientationY(intAxisOrientation::NATURAL); }
1721 //@}
1722
1723 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1724 /** @name Accessor Methods */
1725 //@{
1726 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1727 /** @return The number of pixels in the x direction. */
1728 inline intCrdT getNumPixX() const { return numPixX; }
1729 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1730 /** @return The number of pixels in the y direction. */
1731 inline intCrdT getNumPixY() const { return numPixY; }
1732 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1733 /** Returns a pointer to the raw pixel store.
1734 This generally violates the ramCanvasTpl object interface; however, this may be required for performance.
1735 @return The number a pointer to the raw pixel store. */
1736 colorT *getPixels() { return pixels; }
1737 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1738 /** Return a clone (a copy) of the raw pixel store.
1739 This function copies the internal pixel store and returns a pointer to this copy.
1740 @return Pointer to a copy of the raw pixel store. */
1741 colorT *clonePixels();
1742 //@}
1743
1744 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1745 /** @name Real Coordinate Accessor Methods */
1746 //@{
1747 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1748 fltCrdT getMinRealX() { return minRealX; } //!< x coord of min (real coord)
1749 fltCrdT getMaxRealX() { return maxRealX; } //!< x coord of max (real coord)
1750 fltCrdT getMinRealY() { return minRealY; } //!< y coord of min (real coord)
1751 fltCrdT getMaxRealY() { return maxRealY; } //!< y coord of max (real coord)
1752 fltCrdT getPixWidX() { return pixWidX; } //!< Width of a pixel (real coord)
1753 fltCrdT getPixWidY() { return pixWidY; } //!< Height of a pixel (real coord)
1754 fltCrdT getCanvasWidX() { return canvasWidX; } //!< Width of the display (real coord)
1755 fltCrdT getCanvasWidY() { return canvasWidY; } //!< height of the display(real coord)
1756 fltCrdT getCanvasWidD() { return std::hypot(canvasWidX, canvasWidY); } //!< Width of the display (real coord)
1757 //@}
1758
1759 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1760 /** @name Pixel Value Accessor Methods */
1761 //@{
1762 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1763 /** Returns a copy of the color at the given coordinates. */
1764 colorT getPxColor(intCrdT x, intCrdT y) const;
1765 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1766 /** @overload */
1767 inline colorT getPxColor(fltCrdT x, fltCrdT y) const { return getPxColor(real2intX(x), real2intY(y)); }
1768 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1769 /** @overload */
1770 inline colorT getPxColor(pointIntType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1771 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1772 /** @overload */
1773 inline colorT getPxColor(pointFltType thePoint) const { return getPxColor(thePoint.x, thePoint.y); }
1774 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1775 /** Returns a copy of the color at the given coordinates wrapping x & y if out of range. */
1776 inline colorT getPxColorWrap(intCrdT x, intCrdT y) const { return getPxColorNC(mjr::math::ivl::wrapCO(x, numPixX), mjr::math::ivl::wrapCO(y, numPixY)); }
1777 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1778 /** @overload */
1779 inline colorT getPxColorWrap(fltCrdT x, fltCrdT y) const { return getPxColorWrap(real2intX(x), real2intY(y)); }
1780 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1781 /** @overload */
1782 inline colorT getPxColorWrap(pointIntType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y); }
1783 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1784 /** @overload */
1785 inline colorT getPxColorWrap(pointFltType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y); }
1786 //@}
1787
1788 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1789 /** @name Pixel Channel Value Accessor Methods. */
1790 //@{
1791 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1792 /** Returns a copy of the color channel value at the given coordinates wrapping x & y if out of range. */
1793 template <int chanNum>
1794 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1795 inline colorChanType getPxColorChanWrap(intCrdT x, intCrdT y) const { return getPxColorWrap(x, y).getChanNC(chanNum); }
1796 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1797 /** @overload */
1798 template <int chanNum>
1799 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1800 inline colorChanType getPxColorChanWrap(fltCrdT x, fltCrdT y) const { return getPxColorWrap(real2intX(x), real2intY(y)).getChanNC(chanNum); }
1801 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1802 /** @overload */
1803 template <int chanNum>
1804 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1805 inline colorChanType getPxColorChanWrap(pointIntType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y).getChanNC(chanNum); }
1806 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1807 /** @overload */
1808 template <int chanNum>
1809 requires((chanNum >= 0) && (chanNum < colorT::channelCount))
1810 inline colorChanType getPxColorChanWrap(pointFltType thePoint) const { return getPxColorWrap(thePoint.x, thePoint.y).getChanNC(chanNum); }
1811 //@}
1812
1813 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1814 /** @name Pixel Value Accessor with Interpolation Methods */
1815 //@{
1816 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1817 /** Returns the interpolated color value at the the given coordinates using the given interpolation method.
1818 @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)
1819 @param y The y coordinate
1820 @param interpMethod The interpolation method (default: interpolationType::BILINEAR)
1821 @return Interpolated color value */
1822 colorT getPxColorInterpolate(double x, double y, interpolationType interpMethod = interpolationType::BILINEAR);
1823 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1824 /** Returns the bilinear interpolated color value at the the given coordinates.
1825 @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)
1826 @param y The y coordinate
1827 @return Interpolated color value */
1828 colorT getPxColorInterpBLin(double x, double y);
1829 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1830 /** Returns the truncated interpolated color value at the the given coordinates.
1831 @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)
1832 @param y The y coordinate
1833 @return Interpolated color value */
1834 colorT getPxColorInterpTrunc(double x, double y);
1835 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1836 /** Returns the nearest neighbor interpolated color value at the the given coordinates.
1837 @param x The x coordinate (the type is double, but the coordinate is in the integer coordinate space. i.e. x=1.5 is between x=1 and x=2)
1838 @param y The y coordinate
1839 @return Interpolated color value */
1840 colorT getPxColorInterpNear(double x, double y);
1841 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1842 /** Returns the average 4 interpolated color value at the the given coordinates.
1843 @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)
1844 @param y The y coordinate
1845 @return Interpolated color value */
1846 colorT getPxColorInterpAvg4(double x, double y);
1847 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1848 /** Returns the average 9 interpolated color value at the the given coordinates.
1849 @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)
1850 @param y The y coordinate
1851 @return Interpolated color value */
1852 colorT getPxColorInterpAvg9(double x, double y);
1853 //@}
1854
1855 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1856 /** @name NC stands for No Checks and No Clipping */
1857 /** 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
1858 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
1859 very careful code that handles clipping and error checking by itself -- a good line drawing algorithm for example. */
1860 //@{
1861 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1862 /** Draw a point with no clipping or bounds checking.
1863 @param x The x coordinate of the point to be drawn
1864 @param y The y coordinate of the point to be drawn
1865 @param color The color to draw the point. */
1866 void drawPointNC(intCrdT x, intCrdT y, colorArgType color);
1867 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1868 /** Get the default point to the specified coordinates with no clipping or bounds checking.
1869 @param x The x coordinate of the point
1870 @param y The y coordinate of the point */
1871 inline colorT getPxColorNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1872 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1873 /** Returns a reference to the color object for the given pixel with no clipping or bounds checking.
1874 @param x The x coordinate of the point
1875 @param y The y coordinate of the point
1876 @return Reference to the color object associated with the specified point */
1877 inline colorT& getPxColorRefNC(intCrdT x, intCrdT y) const { return pixels[numPixX * y + x]; }
1878 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1879 /** Draw a horizontal line with no clipping or bounds checking.
1880 @param xMin The MINIMUM x coordinate of the line to be drawn
1881 @param xMax The MAXIMUM x coordinate of the line to be drawn
1882 @param yConst The y coordinate at which the line is to be drawn
1883 @param color The color to draw the line */
1884 inline void drawHorzLineNC(intCrdT xMin, intCrdT xMax, intCrdT yConst, colorArgType color) { for(intCrdT x=xMin;x<=xMax;x++) drawPointNC(x, yConst, color); }
1885 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1886 /** Draw a vertical line with no clipping or bounds checking.
1887 @param yMin The MINIMUM y coordinate of the line to be drawn
1888 @param yMax The MAXIMUM y coordinate of the line to be drawn
1889 @param xConst The x coordinate at which the line is to be drawn
1890 @param color The color to draw the line */
1891 inline void drawVertLineNC(intCrdT yMin, intCrdT yMax, intCrdT xConst, colorArgType color) { for(intCrdT y=yMin;y<=yMax;y++) drawPointNC(xConst, y, color); }
1892 //@}
1893
1894 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1895 /** @name S stands for Simple */
1896 //@{
1897 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1898 /** Draw a point without any special drawing options.
1899 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
1900 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
1901 careful code that handles clipping and error checking and drawing options by itself -- an image filter algorithm for example. Note that enableDrawModes
1902 is ignored.
1903 @param x The x coordinate of the point
1904 @param y The y coordinate of the point
1905 @param color The color with which to draw the point */
1906 inline void drawPointS(intCrdT x, intCrdT y, colorArgType color) { pixels[numPixX * y + x] = color; }
1907 //@}
1908
1909 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1910 /** @name Canvas Level Colorization.
1911 These are tools designed to make things like escape time fractals very easy to create.
1912
1913 @warning These functions are experimental! Functionality and API are likely to change in the future.
1914
1915 */
1916 //@{
1917 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1918 void colorizeFltCanvas(std::function<colorT (fltCrdT, fltCrdT)> cFun);
1919 void colorizeFltCanvas(std::function<colorT (pointFltType)> cFun);
1920
1921 void colorizeIntCanvas(std::function<colorT (intCrdT, intCrdT)> cFun);
1922 void colorizeIntCanvas(std::function<colorT (pointIntType)> cFun);
1923 //@}
1924
1925 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1926 /** @name Canvas Level Statistical Computation.
1927 */
1928 //@{
1929 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1930 intCrdT statNumNonZeroPixels(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
1931 intCrdT retCount = 0;
1932 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
1933 if(x1 > x2)
1934 std::swap(x1, x2);
1935 if(y1 > y2)
1936 std::swap(y1, y2);
1937 for(intCrdT y=y1;y<=y2;y++)
1938 for(intCrdT x=x1;x<=x2;x++)
1939 //if ( !(getPxColor(x, y).isBlack()))
1940 if ( !(getPxColorRefNC(x, y).isBlack()))
1941 retCount++;
1942 }
1943 return(retCount);
1944 }
1945 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1947 return statNumNonZeroPixels(0, 0, numPixX-1, numPixY-1);
1948 }
1949 //@}
1950 };
1951
1952 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1953 // Constructor
1954 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1955 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1957 newIntCoordsNC(-1, -1);
1958 newRealCoords(0.0, 0.0, 0.0, 0.0);
1959 pixels = NULL;
1960 pixelsE = NULL;
1961 setRealAxisDefaultOrientation();
1962 setIntAxisDefaultOrientation();
1963 setDefaultDrawMode();
1964 }
1965
1966 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1967 // Copy Constructor
1968 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1969 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1971 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1972 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1973 pixels = new colorT[theCanvas.numPixX * theCanvas.numPixY];
1974 pixelsE = pixels + (theCanvas.numPixX * theCanvas.numPixY);
1975 realAxOrientationX = theCanvas.realAxOrientationX;
1976 realAxOrientationY = theCanvas.realAxOrientationY;
1977 intAxOrientationX = theCanvas.intAxOrientationX;
1978 intAxOrientationY = theCanvas.intAxOrientationY;
1979 drawMode = theCanvas.drawMode;
1980 for(intCrdT y=0; y<numPixY; y++)
1981 for(intCrdT x=0; x<numPixX; x++)
1982 getPxColorRefNC(x, y) = theCanvas.getPxColorRefNC(x, y);
1983 }
1984
1985 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1986 // Move constructor
1987 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
1988 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
1990 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
1991 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
1992 realAxOrientationX = theCanvas.realAxOrientationX;
1993 realAxOrientationY = theCanvas.realAxOrientationY;
1994 intAxOrientationX = theCanvas.intAxOrientationX;
1995 intAxOrientationY = theCanvas.intAxOrientationY;
1996 drawMode = theCanvas.drawMode;
1997 pixels = theCanvas.pixels;
1998 pixelsE = theCanvas.pixelsE;
1999 }
2000
2001////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2002// Move assignment operator
2003 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2004 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2007 if (this != &theCanvas) {
2008 newIntCoordsNC(theCanvas.numPixX, theCanvas.numPixY);
2009 newRealCoords(theCanvas.minRealX, theCanvas.maxRealX, theCanvas.minRealY, theCanvas.maxRealY);
2010 realAxOrientationX = theCanvas.realAxOrientationX;
2011 realAxOrientationY = theCanvas.realAxOrientationY;
2012 intAxOrientationX = theCanvas.intAxOrientationX;
2013 intAxOrientationY = theCanvas.intAxOrientationY;
2014 drawMode = theCanvas.drawMode;
2015 pixels = theCanvas.pixels;
2016 pixelsE = theCanvas.pixelsE;
2017 }
2018 return *this;
2019 }
2020
2021////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2022 // Normal Constructor
2023 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2024 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2025 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::ramCanvasTpl(intCrdT numPixX_p, intCrdT numPixY_p, fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
2026 newIntCoordsNC(numPixX_p, numPixY_p);
2027 newRealCoords(minRealX_p, maxRealX_p, minRealY_p, maxRealY_p);
2028 pixels = new colorT[numPixX * numPixY];
2029 pixelsE = pixels + (numPixX * numPixY);
2030 setRealAxisDefaultOrientation();
2031 setIntAxisDefaultOrientation();
2032 setDefaultDrawMode();
2033 clrCanvasToBlack();
2034 }
2035
2036////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2037 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2038 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2040 if(pixels != NULL) {
2041 delete[] pixels;
2042 pixels = NULL;
2043 }
2044 }
2045
2046////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2047 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2048 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2049 inline void
2051 if(numPixX_p > intCrdMax) {
2052 throw std::invalid_argument("newIntCoordsNC: numPixX_p argument too large.");
2053 } else if (numPixY_p > intCrdMax) {
2054 throw std::invalid_argument("newIntCoordsNC: numPixY_p argument too large.");
2055 } else {
2056 numPix = numPixX_p * numPixY_p;;
2057 numPixX = numPixX_p;
2058 numPixY = numPixY_p;
2059 }
2060 }
2061
2062////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2063 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2064 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2065 inline void
2066 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::newRealCoords(fltCrdT minRealX_p, fltCrdT maxRealX_p, fltCrdT minRealY_p, fltCrdT maxRealY_p) {
2067 if(minRealX_p > maxRealX_p) {
2068 throw std::invalid_argument("newRealCoords: minRealX_p > maxRealX_p.");
2069 } else if (minRealY_p > maxRealY_p) {
2070 throw std::invalid_argument("newRealCoords: minRealY_p > maxRealY_p.");
2071 } else {
2072 minRealX = minRealX_p;
2073 maxRealX = maxRealX_p;
2074 minRealY = minRealY_p;
2075 maxRealY = maxRealY_p;
2076 updRealCoords();
2077 }
2078 }
2079
2080////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2081 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2082 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2083 inline void
2085 canvasWidX = maxRealX - minRealX;
2086 canvasWidY = maxRealY - minRealY;
2087 pixWidX = (numPixX == 0 ? 0 : canvasWidX / numPixX); // This will cause /0 later if anyone tries to use a coordinate conversion
2088 pixWidY = (numPixY == 0 ? 0 : canvasWidY / numPixY); // This will cause /0 later if anyone tries to use a coordinate conversion
2089 }
2090
2091////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2092 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2093 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2094 inline void
2096 for(intCrdT y=0; y<numPixY; y++)
2097 for(intCrdT x=0; x<numPixX; x++)
2098 getPxColorRefNC(x, y).setChanToMin(chan);
2099 }
2100
2101////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2102 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2103 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2104 inline void
2106 for(intCrdT y=0; y<numPixY; y++)
2107 for(intCrdT x=0; x<numPixX; x++)
2108 getPxColorRefNC(x, y).setChanToMax(chan);
2109 }
2110
2111////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2112 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2113 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2114 inline void
2116 ////// Diffrent ways to do it -- unless otherwise noted, all of them are about the same performance with GCC if colorT has a fast mask
2117
2118 //// Use std:memset
2119 // std::memset((void*)pixels, 0, numPix*sizeof(colorT));
2120
2121 //// Use std::fill
2122 // colorT black;
2123 // black.setToBlack();
2124 // std::fill(pixels, pixelsE, black);
2125
2126 //// Loop over pixel array
2127 // for(colorT* p=pixels; p<pixelsE; p++)
2128 // p->setToBlack();
2129
2130 //// loop over x & y coordinates
2131 for(intCrdT y=0; y<numPixY; y++)
2132 for(intCrdT x=0; x<numPixX; x++)
2133 getPxColorRefNC(x, y).setToBlack();
2134
2135 //// Call clrCanvas with black (this one is *way* slower)
2136 // clrCanvas(colorT(colorCornerEnum::BLACK));
2137 }
2138
2139////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2140 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2141 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2142 inline void
2144 for(intCrdT y=0; y<numPixY; y++)
2145 for(intCrdT x=0; x<numPixX; x++)
2146 getPxColorRefNC(x, y).setToWhite();
2147 }
2148
2149////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2150 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2151 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2152 inline void
2156
2157////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2158 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2159 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2160 inline void
2162 for(intCrdT y=0; y<numPixY; y++)
2163 for(intCrdT x=0; x<numPixX; x++)
2164 drawPointS(x, y, color);
2165 }
2166
2167////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2168 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2169 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2170 void
2172 colorChanType cmin = colorT::maxChanVal;
2173 colorChanType cmax = colorT::minChanVal;
2174 for(intCrdT y=0;y<numPixY;y++) {
2175 for(intCrdT x=0;x<numPixX;x++) {
2176 colorT daColor = getPxColorNC(x, y);
2177 colorChanType curMin = daColor.getMinC();
2178 colorChanType curMax = daColor.getMaxC();
2179 if(curMax > cmax)
2180 cmax = curMax;
2181 if(curMin < cmin)
2182 cmin = curMin;
2183 }
2184 }
2185 if(cmax-cmin > 0) {
2186 double c = 1.0 * static_cast<double>(colorT::maxChanVal-colorT::minChanVal) / static_cast<double>(cmax-cmin);
2187 double b = static_cast<double>(colorT::maxChanVal) - 1.0 * c * static_cast<double>(cmax);
2188 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScale, c, b);
2189 }
2190 }
2191
2192////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2193 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2194 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2195 void
2197 colorT cmin; cmin.setChans(cmin.maxChanVal);
2198 colorT cmax; cmax.setChans(cmin.minChanVal);
2199 for(intCrdT y=0;y<numPixY;y++) {
2200 for(intCrdT x=0;x<numPixX;x++) {
2201 colorT daColor = getPxColorNC(x, y);
2202 cmin.tfrmMin(daColor);
2203 cmax.tfrmMax(daColor);
2204 }
2205 }
2206 colorChanType absCompMin = cmin.getMinC();
2207 colorChanType absCompMax = cmax.getMaxC();
2208 if(absCompMax-absCompMin > 0) {
2209 double rc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getRed()-cmin.getRed());
2210 double rb = cmin.maxChanVal - 1.0*rc*cmax.getRed();
2211 double gc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getGreen()-cmin.getGreen());
2212 double gb = cmin.maxChanVal - 1.0*gc*cmax.getGreen();
2213 double bc = 1.0*static_cast<double>(cmin.maxChanVal-cmin.minChanVal)/static_cast<double>(cmax.getBlue()-cmin.getBlue());
2214 double bb = cmin.maxChanVal - 1.0*bc*cmax.getBlue();
2215 applyHomoPixTfrm(&colorT::tfrmLinearGreyLevelScaleRGB, rc, rb, gc, gb, bc, bb);
2216 }
2217 }
2218
2219////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2220 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2221 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2222 inline void
2224 for(intCrdT y=0; y<numPixY; y++)
2225 for(intCrdT x=0; x<numPixX; x++)
2226 (getPxColorRefNC(x, y).*HPT)();
2227 }
2228
2229////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2230 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2231 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2232 inline void
2234 for(intCrdT y=0; y<numPixY; y++)
2235 for(intCrdT x=0; x<numPixX; x++)
2236 (getPxColorRefNC(x, y).*HPT)(arg1);
2237 }
2238
2239////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2240 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2241 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2242 inline void
2243 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT), colorT arg1, colorT arg2) {
2244 for(intCrdT y=0; y<numPixY; y++)
2245 for(intCrdT x=0; x<numPixX; x++)
2246 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2247 }
2248
2249////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2250 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2251 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2252 inline void
2253 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3) {
2254 for(intCrdT y=0; y<numPixY; y++)
2255 for(intCrdT x=0; x<numPixX; x++)
2256 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2257 }
2258
2259////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2260 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2261 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2262 inline void
2263 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(colorT, colorT, colorT, colorT), colorT arg1, colorT arg2, colorT arg3, colorT arg4) {
2264 for(intCrdT y=0; y<numPixY; y++)
2265 for(intCrdT x=0; x<numPixX; x++)
2266 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2267 }
2268
2269////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2270 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2271 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2272 inline void
2274 for(intCrdT y=0; y<numPixY; y++)
2275 for(intCrdT x=0; x<numPixX; x++)
2276 (getPxColorRefNC(x, y).*HPT)(arg1);
2277 }
2278
2279////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2280 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2281 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2282 inline void
2283 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int), int arg1, int arg2) {
2284 for(intCrdT y=0; y<numPixY; y++)
2285 for(intCrdT x=0; x<numPixX; x++)
2286 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2287 }
2288
2289////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2290 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2291 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2292 inline void
2293 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int), int arg1, int arg2, int arg3) {
2294 for(intCrdT y=0; y<numPixY; y++)
2295 for(intCrdT x=0; x<numPixX; x++)
2296 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2297 }
2298
2299////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2300 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2301 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2302 inline void
2303 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(int, int, int, int), int arg1, int arg2, int arg3, int arg4) {
2304 for(intCrdT y=0; y<numPixY; y++)
2305 for(intCrdT x=0; x<numPixX; x++)
2306 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2307 }
2308
2309////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2310 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2311 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2312 inline void
2314 for(intCrdT y=0; y<numPixY; y++)
2315 for(intCrdT x=0; x<numPixX; x++)
2316 (getPxColorRefNC(x, y).*HPT)(arg1);
2317 }
2318
2319////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2320 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2321 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2322 inline void
2323 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double), double arg1, double arg2) {
2324 for(intCrdT y=0; y<numPixY; y++)
2325 for(intCrdT x=0; x<numPixX; x++)
2326 (getPxColorRefNC(x, y).*HPT)(arg1, arg2);
2327 }
2328
2329////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2330 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2331 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2332 inline void
2333 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double), double arg1, double arg2, double arg3) {
2334 for(intCrdT y=0; y<numPixY; y++)
2335 for(intCrdT x=0; x<numPixX; x++)
2336 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3);
2337 }
2338
2339////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2340 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2341 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2342 inline void
2343 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double),
2344 double arg1, double arg2, double arg3, double arg4) {
2345 for(intCrdT y=0; y<numPixY; y++)
2346 for(intCrdT x=0; x<numPixX; x++)
2347 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4);
2348 }
2349
2350////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2351 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2352 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2353 inline void
2354 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double),
2355 double arg1, double arg2, double arg3, double arg4, double arg5) {
2356 for(intCrdT y=0; y<numPixY; y++)
2357 for(intCrdT x=0; x<numPixX; x++)
2358 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5);
2359 }
2360
2361////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2362 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2363 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2364 inline void ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::applyHomoPixTfrm(colorT& (colorT::*HPT)(double, double, double, double, double, double),
2365 double arg1, double arg2, double arg3, double arg4, double arg5, double arg6) {
2366 for(intCrdT y=0; y<numPixY; y++)
2367 for(intCrdT x=0; x<numPixX; x++)
2368 (getPxColorRefNC(x, y).*HPT)(arg1, arg2, arg3, arg4, arg5, arg6);
2369 }
2370
2371////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2372 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2373 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2375 const ramCanvasTpl &theCanvas,
2376 intCrdT trgX, intCrdT trgY,
2377 intCrdT wide, intCrdT tall,
2378 intCrdT srcX, intCrdT srcY) {
2379 // Figure out real default width
2380 if(wide < 0)
2381 wide = numPixX-trgX;
2382
2383 // Make sure wide is not wider than current canvas.
2384 if(wide > (numPixX-srcX))
2385 wide = theCanvas.getNumPixX()-srcX;
2386
2387 // Make sure wide is not wider than given canvas.
2388 if(wide > (theCanvas.getNumPixX()-srcX))
2389 wide = theCanvas.getNumPixX()-srcX;
2390
2391 // Figure out real default tall
2392 if(tall < 0)
2393 tall = numPixY-srcY;
2394
2395 // Make sure tall is not taller than current canvas.
2396 if(tall > (numPixY-srcY))
2397 tall = numPixY-srcY;
2398
2399 // Make sure tall is not taller than given canvas.
2400 if(tall > (theCanvas.getNumPixY()-srcY))
2401 tall = theCanvas.getNumPixY()-srcY;
2402
2403 intCrdT xMax = trgX+wide;
2404 intCrdT yMax = trgY+tall;
2405 for(intCrdT y=trgY, ys=srcY; y<yMax; y++, ys++)
2406 for(intCrdT x=trgX, xs=srcX; x<xMax; x++, xs++)
2407 (getPxColorRefNC(x, y).*HPT)(theCanvas.getPxColor(xs, ys));
2408 }
2409
2410////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2411 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2412 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2413 void
2414 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawLine(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
2415 moveTo(x2, y2); // Do this first
2416 intCrdT x, y;
2417 if(y1 == y2) { // slope = 0
2418 if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
2419 return;
2420 if(x1 > x2) // . Fix point ordering
2421 std::swap(x1, x2);
2422 if(x1 < 0) // . Clip left
2423 x1 = 0;
2424 if(x2 >= numPixX) // . Clip right
2425 x2 = numPixX - 1;
2426 drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
2427 } else if(x1 == x2) { // slope = infinity
2428 if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
2429 return;
2430 if(y1 > y2) // . Fix point ordering
2431 std::swap(y1, y2);
2432 if(y1 < 0) // . Clip top
2433 y1 = 0;
2434 if(y2 >= numPixY) // . Clip bottom
2435 y2 = numPixY - 1;
2436 drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
2437 } else { // Slope is not infinity or 0...
2438 int dx, dy;
2439 if(x1 > x2) { // . Fix point ordering
2440 std::swap(x1, x2);
2441 std::swap(y1, y2);
2442 }
2443 dx = x2 - x1; // . Compute the slope
2444 dy = y2 - y1;
2445 if(dx == dy) { // . Slope = 1
2446 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
2447 return;
2448 if(x1 < 0) { // .. Clip left
2449 y1 = y1 - x1;
2450 x1 = 0;
2451 }
2452 if(y1 < 0) { // .. Clip top
2453 x1 = x1 - y1;
2454 y1 = 0;
2455 }
2456 if(x2 >= numPixX) { // .. Clip right
2457 y2 = y2 - (x2 - numPixX) - 1;
2458 x2 = numPixX - 1;
2459 }
2460 if(y2 >= numPixY) { // .. Clip bottom
2461 x2 = x2 - (y2 - numPixY) - 1;
2462 y2 = numPixY - 1;
2463 }
2464 for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
2465 drawPointNC(x, y, color);
2466 } else if(dx == -dy) { // . Slope = -1
2467 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
2468 return;
2469 if(x1 < 0) { // .. Clip left
2470 y1 = y1 + x1;
2471 x1 = 0;
2472 }
2473 if(x2 >= numPixX) { // .. Clip right
2474 y2 = y2 + (x2 - (numPixX - 1));
2475 x2 = numPixX - 1;
2476 }
2477 if(y2 < 0) { // .. Clip top
2478 x2 = x2 + y2;
2479 y2 = 0;
2480 }
2481 if(y1 >= numPixY) { // .. Clip bottom
2482 x1 = x1 + (y1 - (numPixY - 1));
2483 y1 = numPixY - 1;
2484 }
2485 for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
2486 drawPointNC(x, y, color);
2487 } else { // . Slope != 1, -1, 0, \infinity
2488 int s, dx2, dy2;
2489 dx2 = 2*dx;
2490 dy2 = 2*dy;
2491 if(dy > 0) { // .. Positive Slope
2492 if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
2493 return;
2494 if(x1 < 0) { // ... Clip left
2495 y1 = (int)(1.0*y1-x1*dy/dx);
2496 x1 = 0;
2497 }
2498 if(y1 < 0) { // ... Clip top
2499 x1 = (int)(1.0*x1-y1*dx/dy);
2500 y1 = 0;
2501 }
2502 if(x2 >= numPixX) { // ... Clip right
2503 y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
2504 x2 = numPixX - 1;
2505 }
2506 if(y2 >= numPixY) { // ... Clip bottom
2507 x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
2508 y2 = numPixY - 1;
2509 }
2510// MJR TODO NOTE drawLine: We use drawPoint instead of drawPointNC, can we make an off canvas decesion instead? Similar case down below.
2511 if(dx > dy) { // ... 0 < Slope < 1
2512 s = dy2 - dx;
2513 x=x1;
2514 y=y1;
2515 while(x<=x2) { // .... Draw Line
2516 drawPoint(x, y, color);
2517 if(s < 0) {
2518 s += dy2;
2519 } else {
2520 y++;
2521 s += dy2 - dx2;
2522 }
2523 x++;
2524 }
2525 } else { // ... 1 < Slope < infinity
2526 s = dy - dx2;
2527 x=x1;
2528 y=y1;
2529 while(y<=y2) { // .... Draw Line
2530 drawPoint(x, y, color);
2531 if(s > 0) {
2532 s -= dx2;
2533 } else {
2534 x++;
2535 s += dy2 - dx2;
2536 }
2537 y++;
2538 }
2539 }
2540 } else { // .. Negative Slope
2541 if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
2542 return;
2543 if(x1 < 0) { // ... Clip left
2544 y1 = (int)(1.0*y1-x1*dy/dx);
2545 x1 = 0;
2546 }
2547 if(y2 < 0) { // ... Clip top
2548 x2 = (int)(1.0*x2-y2*dx/dy);
2549 y2 = 0;
2550 }
2551 if(x2 >= numPixX) { // ... Clip right
2552 y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
2553 x2 = numPixX - 1;
2554 }
2555 if(y1 >= numPixY) { // ... Clip bottom
2556 x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
2557 y1 = numPixY - 1;
2558 }
2559 if(dx > -dy) { // ... 0 > Slope > -infinity
2560 s = dy2 + dx;
2561 x=x1;
2562 y=y1;
2563 while(x<=x2) { // .... Draw Line
2564 drawPoint(x, y, color);
2565 if(s > 0) {
2566 s += dy2;
2567 } else {
2568 y--;
2569 s += dy2 + dx2;
2570 }
2571 x++;
2572 }
2573 } else { // ... -1 > Slope > -inf
2574 s = dy + dx2;
2575 x=x1;
2576 y=y1;
2577 while(y>=y2) { // .... Draw Line
2578 drawPoint(x, y, color);
2579 if(s < 0) {
2580 s += dx2;
2581 } else {
2582 x++;
2583 s += dy2 + dx2;
2584 }
2585 y--;
2586 }
2587 }
2588 }
2589 }
2590 }
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
2598 newIntCoordsNC(-1, -1);
2599 if(pixels != NULL) {
2600 delete[] pixels;
2601 pixels=NULL;
2602 pixelsE=NULL;
2603 }
2604 }
2605
2606////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2607 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2608 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2609 void
2610 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::rePointPixels(colorT *new_pixels, intCrdT new_numPixX, intCrdT new_numPixY) {
2611 freeCanvas();
2612 newIntCoordsNC(new_numPixX, new_numPixY);
2613 updRealCoords();
2614 if(new_pixels != NULL)
2615 pixels = new_pixels;
2616 if(pixels == NULL)
2617 pixelsE = NULL;
2618 else
2619 pixelsE = pixels+(new_numPixX * new_numPixY);
2620 }
2621
2622////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2623 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2624 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2625 void
2627 if((numPixX_p<=0) || (numPixY_p<=0)) {
2628 freeCanvas();
2629 } else {
2630 if( (numPixX_p!=numPixX) || (numPixY_p!=numPixY) ) {
2631 colorT *new_pixels = new colorT[numPixX_p * numPixY_p];
2632 rePointPixels(new_pixels, numPixX_p, numPixY_p);
2633 } else {
2634 // Don't really do anything as the new size is the same as the old size...
2635 }
2636 }
2637 }
2638
2639////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2640 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2641 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2642 void
2644 reallocCanvas(new_numPixX_p, new_numPixY_p);
2645 }
2646
2647////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2648 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2649 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2650 void
2651 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::expandCanvas(intCrdT new_numPixX_p, intCrdT new_numPixY_p, intCrdT x1, intCrdT y1, colorArgType color) {
2652 if( (new_numPixX_p != numPixX) || (new_numPixY_p != numPixY) ) {
2653
2654 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2655
2656 // Fill it up with the default color. Should only draw the ones that need it, but computers are fast...
2657 for(intCrdT y=0;y<new_numPixY_p;y++)
2658 for(intCrdT x=0;x<new_numPixX_p;x++)
2659 new_pixels[new_numPixX_p * (y) + (x)] = color;
2660
2661 intCrdT yMax = std::min(numPixY+y1, new_numPixY_p);
2662 intCrdT xMax = std::min(numPixX+x1, new_numPixX_p);
2663
2664 // Copy the old image to the new space.
2665 if ((x1 < new_numPixX_p) && (y1 < new_numPixY_p))
2666 for(intCrdT y=y1;y<yMax;y++)
2667 for(intCrdT x=x1;x<xMax;x++)
2668 new_pixels[new_numPixX_p * (y) + (x)] = getPxColor(x-x1, y-y1);
2669
2670 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2671 }
2672 }
2673
2674////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2675 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2676 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2677 void
2678 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::cropCanvas(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2) {
2679 if( !isCliped(x1, y1) && !isCliped(x2, y2) ) {
2680 if(x1 > x2)
2681 std::swap(x1, x2);
2682 if(y1 > y2)
2683 std::swap(y1, y2);
2684 intCrdT xp, yp, x, y;
2685 intCrdT new_numPixX_p = x2-x1+1;
2686 intCrdT new_numPixY_p = y2-y1+1;
2687 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2688
2689 // Copy the old image to the new space.
2690 for(y=y1,yp=0;y<=y2;y++,yp++)
2691 for(x=x1,xp=0;x<=x2;x++,xp++)
2692 new_pixels[new_numPixX_p * yp + xp] = getPxColor(x, y);
2693
2694 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2695 }
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 for(intCrdT y=0; y<numPixY/2; y++)
2704 for(intCrdT x=0; x<numPixX; x++) {
2705 colorT aColor = getPxColor(x, numPixY-y-1);
2706 drawPointNC(x, numPixY-y-1, getPxColor(x, y));
2707 drawPointNC(x, y, aColor);
2708 }
2709 }
2710
2711////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2712 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2713 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2714 void
2716 for(intCrdT x=0; x<numPixX/2; x++)
2717 for(intCrdT y=0; y<numPixY; y++) {
2718 colorT aColor = getPxColor(numPixX-x-1, y);
2719 drawPointNC(numPixX-x-1, y, getPxColor(x, y));
2720 drawPointNC(x, y, aColor);
2721 }
2722 }
2723
2724////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2725 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2726 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2727 void
2729 intCrdT new_numPixX_p = numPixY;
2730 intCrdT new_numPixY_p = numPixX;
2731 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2732 for(intCrdT y=0; y<numPixY; y++)
2733 for(intCrdT x=0; x<numPixX; x++)
2734 new_pixels[new_numPixX_p * (x/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2735 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2736 }
2737
2738////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2739 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2740 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2741 void
2743 intCrdT new_numPixX_p = numPixY;
2744 intCrdT new_numPixY_p = numPixX;
2745 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2746 for(intCrdT y=0; y<numPixY; y++)
2747 for(intCrdT x=0; x<numPixX; x++)
2748 new_pixels[new_numPixX_p * (numPixX-x-1/*y-crd*/) + (y/*x-crd*/)] = getPxColor(x, y);
2749 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2750 }
2751
2752////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2753 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2754 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2755 void
2757 intCrdT new_numPixX_p = numPixY;
2758 intCrdT new_numPixY_p = numPixX;
2759 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2760 for(intCrdT y=0; y<numPixY; y++)
2761 for(intCrdT x=0; x<numPixX; x++)
2762 new_pixels[new_numPixX_p * (x/*y-crd*/) + (numPixY-y-1/*x-crd*/)] = getPxColor(x, y);
2763 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2764 }
2765
2766////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2767 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2768 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2769 void
2771 intCrdT new_numPixX_p = numPixX;
2772 intCrdT new_numPixY_p = numPixY;
2773 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
2774 for(intCrdT y=0; y<numPixY; y++)
2775 for(intCrdT x=0; x<numPixX; x++)
2776 new_pixels[new_numPixX_p * (numPixY-y-1/*y-crd*/) + (numPixX-x-1/*x-crd*/)] = getPxColor(x, y);
2777 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
2778 }
2779
2780////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2781 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2782 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2785 unsigned int endiannessProbe = 1;
2786 if(((char *)&endiannessProbe)[0]) {
2787 return endianType::LITTLE;
2788 } else {
2789 return endianType::BIG;
2790 }
2791 }
2792
2793////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2794 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2795 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2796 inline void
2799 int numBytes,
2800 uint64_t data) {
2801 if(numBytes>0) {
2802 if (numBytes == 1) {
2803 uint8_t tmp = (data & 0xff);
2804 oStream.write((const char *)&tmp, 1);
2805 } else {
2806 if (numBytes<9) {
2807 endianType endiannessToUse = (endianness == endianType::AUTO ? platformEndianness() : endianness);
2808 if(endiannessToUse == endianType::LITTLE) {
2809 for(int curByte=0; curByte<numBytes; curByte++) {
2810 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2811 oStream.write((const char *)&tmp, 1);
2812 }
2813 } else {
2814 for(int curByte=(numBytes-1); curByte>=0; curByte--) {
2815 uint8_t tmp = ((data >> (8*curByte)) & 0xff);
2816 oStream.write((const char *)&tmp, 1);
2817 }
2818 }
2819 }
2820 }
2821 }
2822 }
2823
2824////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2825 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2826 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2827 void
2829 for(intCrdT yi=0;yi<numPixY;yi++) {
2830 for(intCrdT xi=0;xi<numPixX;xi++) {
2831 fltCrdT xf = int2realX(xi);
2832 fltCrdT yf = int2realY(yi);
2833 colorT aColor = cFun(xf, yf);
2834 drawPoint(xi, yi, aColor);
2835 }
2836 }
2837 }
2838
2839////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2840 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2841 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2842 void
2844 for(intCrdT yi=0;yi<numPixY;yi++) {
2845 for(intCrdT xi=0;xi<numPixX;xi++) {
2846 pointFltType xyPt(int2realX(xi), int2realY(yi));
2847 colorT aColor = cFun(xyPt);
2848 drawPoint(xi, yi, aColor);
2849 }
2850 }
2851 }
2852
2853////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2854 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2855 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2856 void
2858 for(intCrdT yi=0;yi<numPixY;yi++) {
2859 for(intCrdT xi=0;xi<numPixX;xi++) {
2860 colorT aColor = cFun(xi, yi);
2861 drawPoint(xi, yi, aColor);
2862 }
2863 }
2864 }
2865
2866////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2867 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2868 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2869 void
2871 for(intCrdT yi=0;yi<numPixY;yi++) {
2872 for(intCrdT xi=0;xi<numPixX;xi++) {
2873 pointIntType xyPt(xi, yi);
2874 colorT aColor = cFun(xyPt);
2875 drawPoint(xi, yi, aColor);
2876 }
2877 }
2878 }
2879
2880////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2881 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2882 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2883 inline int
2885
2886 std::ofstream outStream;
2887 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2888 if (outStream.is_open())
2889 outStream.imbue(std::locale::classic());
2890 else
2891 return 1;
2892
2893 if(numPixX < 1) // too skinny
2894 return 6;
2895 if(numPixX > 0xffff) // too wide
2896 return 7;
2897 if(numPixY < 1) // too short
2898 return 8;
2899 if(numPixY > 0xffff) // too tall
2900 return 9;
2901
2902 /* Write header */
2903 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // id length
2904 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colourmaptype
2905 writeUIntToStream(outStream, endianType::LITTLE, 1, 2); // datatypecode: 2 == Truecolor RGB 8-bit, 3 == Monochrome
2906 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit colourmaporigin
2907 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // colurmaplength
2908 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // colormapdepth
2909 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit x_origin
2910 writeUIntToStream(outStream, endianType::LITTLE, 2, 0); // 16-bit y_origon
2911 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixX); // Width
2912 writeUIntToStream(outStream, endianType::LITTLE, 2, numPixY); // Height
2913 writeUIntToStream(outStream, endianType::LITTLE, 1, 24); // bits per pixel
2914 writeUIntToStream(outStream, endianType::LITTLE, 1, 0); // imagedescriptor
2915
2916 /* Write data */
2917 intCrdT x, y;
2918 /* Normally I would not resort to such trickery; however, this is an exception. The following for loop is equivalent to switching between the two forms
2919 "for(y=(numPixY-1); y>=0; y--)" and "for(y=0; y<numPixY; y++)". */
2920 bool yNat = isIntAxOrientationNaturalY();
2921 bool xNat = isIntAxOrientationNaturalX();
2922 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
2923 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
2924 colorT aColor = getPxColorRefNC(x, y);
2925 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestBlueChan()));
2926 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestGreenChan()));
2927 writeUIntToStream(outStream, endianType::LITTLE, 1, aColor.getChan_byte(aColor.bestRedChan()));
2928 }
2929 }
2930 return 0;
2931 }
2932
2933////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2934 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2935 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2936 inline int
2939 return writeRAWfile(fileName, tmp);
2940 }
2941
2942////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2943 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2944 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2945 template <class rcConT>
2946 inline int
2948
2949 std::ofstream outStream;
2950 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
2951 if (outStream.is_open())
2952 outStream.imbue(std::locale::classic());
2953 else
2954 return 1;
2955
2956 outStream << "MJRRAW\n"; // 7 7
2957 outStream << std::setw(19) << std::setfill('0') << rcConverter.getNumPixX() << "x"; // 20 27
2958 outStream << std::setw(19) << std::setfill('0') << rcConverter.getNumPixY() << "y"; // 20 47
2959 outStream << std::setw(27) << std::setfill('0') << rcConT::colorType::channelCount << "c"; // 28 75
2960 outStream << std::setw(11) << std::setfill('0') << rcConT::colorType::bitsPerChan << "b"; // 12 87
2961 outStream << (rcConT::colorType::chanIsUnsigned ? "UNS" : "SGN") << "s"; // 4 91
2962 outStream << (rcConT::colorType::chanIsInt ? "INT" : "FLT") << "t"; // 4 95
2963 outStream << (platformEndianness() == endianType::LITTLE ? "LTL" : "BIG") << "i"; // 4 99
2964 outStream << "\n"; // 1 100
2965
2966 intCrdT x, y;
2967 /* 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
2968 "for(y=(rcConverter.getNumPixY()-1); y>=0; y--)" and "for(y=0; y<rcConverter.getNumPixY(); y++)". */
2969 bool yNat = !(rcConverter.isIntAxOrientationNaturalY());
2970 bool xNat = rcConverter.isIntAxOrientationNaturalX();
2971 for((yNat?y=0:y=(rcConverter.getNumPixY()-1)); (yNat?y<rcConverter.getNumPixY():y>=0); (yNat?y++:y--)) {
2972 for((xNat?x=0:x=(rcConverter.getNumPixX()-1)); (xNat?x<rcConverter.getNumPixX():x>=0); (xNat?x++:x--)) {
2973 typename rcConT::colorType aColor = rcConverter.getPxColorNC(x, y);
2974 for(int c=0; c<aColor.channelCount; c++) {
2975 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
2976 outStream.write((const char *)&aChanValue, sizeof(colorChanType));
2977 }
2978 }
2979 }
2980 return 0;
2981 }
2982
2983////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2984 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2985 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2986 inline int
2989 return writeTIFFfile(fileName, tmp, markAlpha);
2990}
2991
2992////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2993 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
2994 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
2995 template <class rcConT>
2996 inline int
2997 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::writeTIFFfile(std::string fileName, rcConT rcConverter, bool markAlpha) {
2998
2999 if(rcConT::colorType::bitsPerChan < 8) // channels too thin
3000 return 2;
3001 if(rcConT::colorType::bitsPerChan > 0xffff) // channels too fat
3002 return 3;
3003 if(rcConT::colorType::channelCount < 1) // too few channels
3004 return 4;
3005 if(rcConT::colorType::channelCount > 0xffff) // too many channels
3006 return 5;
3007 if(rcConverter.getNumPixX() < 1) // too skinny
3008 return 6;
3009 if(rcConverter.getNumPixX() > 0x7fffffff) // too wide
3010 return 7;
3011 if(rcConverter.getNumPixY() < 1) // too short
3012 return 8;
3013 if(rcConverter.getNumPixY() > 0x7fffffff) // too tall
3014 return 9;
3015 unsigned long bytesPerRow = rcConverter.getNumPixX() * rcConT::colorType::bitsPerChan / 8ul * rcConT::colorType::channelCount;
3016 if(bytesPerRow > 0xffffffff) // rows too big
3017 return 10;
3018 if(bytesPerRow * rcConverter.getNumPixY() > 0xfffffffff) // image too big
3019 return 11;
3020
3021 // //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
3022 const uint16_t tcTIFF_BIGENDIAN = 0x4d4d; /* Magic number for big endian */
3023 const uint16_t tcTIFF_LITTLEENDIAN = 0x4949; /* Magic number for little endian */
3024 const uint16_t tcPHOTOMETRIC_MINISBLACK = 1; /* min value is black */
3025 const uint16_t tcPHOTOMETRIC_RGB = 2; /* RGB color model */
3026 const uint16_t tcORIENTATION_TOPLEFT = 1; /* row 0 top, col 0 lhs */
3027 const uint16_t tcPLANARCONFIG_CONTIG = 1; /* single image plane */
3028 const uint16_t tcRESUNIT_NONE = 1; /* no meaningful units */
3029 const uint16_t tcSAMPLEFORMAT_UINT = 1; /* !unsigned integer data */
3030 const uint16_t tcSAMPLEFORMAT_IEEEFP = 3; /* !IEEE floating point data */
3031
3032 // //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
3033 // const uint16_t tcTIFFTAG_IMAGEWIDTH = 256; /* image width in pixels */
3034 // const uint16_t tcTIFFTAG_IMAGELENGTH = 257; /* image height in pixels */
3035 // const uint16_t tcTIFFTAG_BITSPERSAMPLE = 258; /* bits per channel (sample) */
3036 // const uint16_t tcTIFFTAG_COMPRESSION = 259; /* data compression technique */
3037 // const uint16_t tcTIFFTAG_PHOTOMETRIC = 262; /* photometric interpretation */
3038 // const uint16_t tcTIFFTAG_STRIPOFFSETS = 273; /* offsets to data strips */
3039 // const uint16_t tcTIFFTAG_ORIENTATION = 274; /* +image orientation */
3040 // const uint16_t tcTIFFTAG_SAMPLESPERPIXEL = 277; /* samples per pixel */
3041 // const uint16_t tcTIFFTAG_ROWSPERSTRIP = 278; /* rows per strip of data */
3042 // const uint16_t tcTIFFTAG_STRIPBYTECOUNTS = 279; /* bytes counts for strips */
3043 // const uint16_t tcTIFFTAG_XRESOLUTION = 282; /* pixels/resolution in x */
3044 // const uint16_t tcTIFFTAG_YRESOLUTION = 283; /* pixels/resolution in y */
3045 // const uint16_t tcTIFFTAG_PLANARCONFIG = 284; /* storage organization */
3046 // const uint16_t tcTIFFTAG_RESOLUTIONUNIT = 296; /* units of resolutions */
3047 // const uint16_t tcTIFFTAG_EXTRASAMPLES = 338; /* !info about extra samples */
3048 // const uint16_t tcTIFFTAG_SAMPLEFORMAT = 339; /* !data sample format */
3049
3050 endianType fe = platformEndianness(); // Endian Type
3051 uint16_t endianNum = (fe == endianType::LITTLE ? tcTIFF_LITTLEENDIAN : tcTIFF_BIGENDIAN); // Endianness Magic Number
3052 uint32_t tifWidth = (uint32_t)rcConverter.getNumPixX(); // ImageWidth
3053 uint32_t tifLength = (uint32_t)rcConverter.getNumPixY(); // ImageLength & RowsPerStrip
3054 uint32_t tifSPP = (uint32_t)rcConT::colorType::channelCount; // SamplesPerPixel
3055 uint16_t tifBPS = (uint16_t)(rcConT::colorType::bitsPerChan); // BitsPerSample
3056 uint32_t bytePerSmp = tifBPS / 8; // Bytes per sample
3057 uint32_t tifSBC = tifLength * tifWidth * bytePerSmp * tifSPP; // StripByteCounts
3058 bool haveRGB = tifSPP>=3; // TRUE if this image has RGB data (at least 3 channels)
3059 uint16_t numImgSmp = (haveRGB ? 3 : 1); // Number of samples used for image data (3 for RGB, 1 otherwise)
3060 uint16_t tifPMI = (haveRGB ? tcPHOTOMETRIC_RGB : tcPHOTOMETRIC_MINISBLACK); // PhotometricInterp
3061 uint16_t tifPC = tcPLANARCONFIG_CONTIG; // Planarconfig
3062 uint16_t tifOri = tcORIENTATION_TOPLEFT; // Orientation
3063 uint16_t tifResU = tcRESUNIT_NONE; // Resolution Unit
3064 bool haveXS = !((tifSPP==1) || (tifSPP==3)); // TRUE if this image has ExtraSamples data
3065 bool haveManyXS = tifSPP>4; // TRUE if this image has MORE THAN ONE ExtraSamples data
3066 uint16_t numTags = 1+14 + (haveXS ? 1 : 0); // Number fo tags in this image
3067 bool haveManyBPS = tifSPP>1; // TRUE if this image has MORE THAN ONE BitsPerSample data
3068 uint32_t numXS = tifSPP - numImgSmp; // Number of extra samples
3069 uint32_t xResOff = 14 + 12 * numTags; // XResolution offset
3070 uint32_t yResOff = xResOff + 8; // YResolution offset
3071 uint32_t bpsOff = yResOff + 8; // BitsPerSample offset
3072 uint32_t xsOff = bpsOff + (haveManyBPS ? 2 * tifSPP : 0); // ExtraSamples offset
3073 uint32_t imgOff = xsOff + (haveManyXS ? 2 * numXS : 0); // Image Data offset
3074 uint16_t sampFmt = (rcConT::colorType::chanIsInt ? tcSAMPLEFORMAT_UINT : tcSAMPLEFORMAT_IEEEFP); // SampleFormat (1=unsigned, 3=IEEE)
3075
3076 std::ofstream outStream;
3077 outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
3078 if (outStream.is_open())
3079 outStream.imbue(std::locale::classic());
3080 else
3081 return 1;
3082
3083 writeUIntToStream(outStream, fe, 2, endianNum); // Write: little endian magic number
3084 writeUIntToStream(outStream, fe, 2, 42); // Write: TIFF magic number
3085 writeUIntToStream(outStream, fe, 4, 8); // Write: IDF offset
3086 writeUIntToStream(outStream, fe, 2, numTags); // Tag Count
3087 writeUIntToStream(outStream, fe, 2, 0x100); writeUIntToStream(outStream, fe, 2, 4);
3088 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifWidth); // ImageWidth
3089 writeUIntToStream(outStream, fe, 2, 0x101); writeUIntToStream(outStream, fe, 2, 4);
3090 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // ImageLength
3091 writeUIntToStream(outStream, fe, 2, 0x102); writeUIntToStream(outStream, fe, 2, 3);
3092 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifBPS); writeUIntToStream(outStream, fe, 2, 0); // BitsPerSample
3093 writeUIntToStream(outStream, fe, 2, 0x103); writeUIntToStream(outStream, fe, 2, 3);
3094 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, 1); writeUIntToStream(outStream, fe, 2, 0); // Compression
3095 writeUIntToStream(outStream, fe, 2, 0x106); writeUIntToStream(outStream, fe, 2, 3);
3096 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPMI); writeUIntToStream(outStream, fe, 2, 0); // PhotometricIn
3097 writeUIntToStream(outStream, fe, 2, 0x111); writeUIntToStream(outStream, fe, 2, 4);
3098 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, imgOff); // StripOffsets
3099 writeUIntToStream(outStream, fe, 2, 0x112); writeUIntToStream(outStream, fe, 2, 3);
3100 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifOri); writeUIntToStream(outStream, fe, 2, 0); // Orientation
3101 writeUIntToStream(outStream, fe, 2, 0x115); writeUIntToStream(outStream, fe, 2, 3);
3102 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifSPP); writeUIntToStream(outStream, fe, 2, 0); // SamplesPerPixel
3103 writeUIntToStream(outStream, fe, 2, 0x116); writeUIntToStream(outStream, fe, 2, 4);
3104 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifLength); // RowsPerStrip
3105 writeUIntToStream(outStream, fe, 2, 0x117); writeUIntToStream(outStream, fe, 2, 4);
3106 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, tifSBC); // StripByteCounts
3107 writeUIntToStream(outStream, fe, 2, 0x11A); writeUIntToStream(outStream, fe, 2, 5);
3108 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, xResOff); // XResolution
3109 writeUIntToStream(outStream, fe, 2, 0x11B); writeUIntToStream(outStream, fe, 2, 5);
3110 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, yResOff); // YResolution
3111 writeUIntToStream(outStream, fe, 2, 0x11C); writeUIntToStream(outStream, fe, 2, 3);
3112 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifPC); writeUIntToStream(outStream, fe, 2, 0); // PlanarConf
3113 writeUIntToStream(outStream, fe, 2, 0x128); writeUIntToStream(outStream, fe, 2, 3);
3114 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 2, tifResU); writeUIntToStream(outStream, fe, 2, 0); // ResolutionUnit
3115 if(haveXS) { // ExtraSamples
3116 if(haveManyXS) {
3117 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3118 writeUIntToStream(outStream, fe, 4, numXS); writeUIntToStream(outStream, fe, 4, xsOff);
3119 } else {
3120 if(markAlpha) { // is chan4alpha
3121 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3122 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1);
3123 } else {
3124 writeUIntToStream(outStream, fe, 2, 0x152); writeUIntToStream(outStream, fe, 2, 3);
3125 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 0);
3126 }
3127 }
3128 }
3129
3130 writeUIntToStream(outStream, fe, 2, 0x153);
3131 writeUIntToStream(outStream, fe, 2, 3); writeUIntToStream(outStream, fe, 4, 1);
3132 writeUIntToStream(outStream, fe, 2, sampFmt); writeUIntToStream(outStream, fe, 2, 0); // SampleFormat
3133
3134 writeUIntToStream(outStream, fe, 4, 0); // IFD END
3135 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // XResolutionData
3136 writeUIntToStream(outStream, fe, 4, 1); writeUIntToStream(outStream, fe, 4, 1); // YResolutionData
3137 if(haveManyBPS) { // YResolutionData
3138 for(unsigned int i=0; i<tifSPP; i++)
3139 writeUIntToStream(outStream, fe, 2, tifBPS);
3140 }
3141 if(haveManyXS) // ExtraSamplesData (can't be RGBA is on xtra, not many)
3142 for(unsigned int i=0; i<numXS; i++)
3143 writeUIntToStream(outStream, fe, 4, 0);
3144 // Image data
3145 intCrdT x, y;
3146 bool yNat = !(rcConverter.isIntAxOrientationNaturalY());
3147 bool xNat = rcConverter.isIntAxOrientationNaturalX();
3148 for((yNat?y=0:y=(rcConverter.getNumPixY()-1)); (yNat?y<rcConverter.getNumPixY():y>=0); (yNat?y++:y--)) {
3149 for((xNat?x=0:x=(rcConverter.getNumPixX()-1)); (xNat?x<rcConverter.getNumPixX():x>=0); (xNat?x++:x--)) {
3150 typename rcConT::colorType aColor = rcConverter.getPxColorNC(x, y);
3151 for(int c=0; c<aColor.channelCount; c++) {
3152 typename rcConT::colorType::channelType aChanValue = aColor.getChan(c);
3153 if (rcConT::colorType::chanIsInt)
3154 writeUIntToStream(outStream, fe, bytePerSmp, aChanValue); // Sample Data
3155 else
3156 outStream.write((const char *)&aChanValue, bytePerSmp); // Sample Data
3157 }
3158 }
3159 }
3160
3161 return 0;
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 int
3169 intCrdT x1, intCrdT y1,
3170 intCrdT x2, intCrdT y2,
3171 int redChan, int greenChan, int blueChan, int alphaChan) {
3172 if(x1 > x2) // Get x1 < x2
3173 std::swap(x1, x2);
3174 if(y1 > y2) // Get y1 < y2
3175 std::swap(y1, y2);
3176
3177 if(x1 < 0) return 1; // Outside of canvas
3178 if(x2 >= numPixX) return 1; // Outside of canvas
3179 if(y1 < 0) return 1; // Outside of canvas
3180 if(y2 >= numPixY) return 1; // Outside of canvas
3181 if(x2 < x1) return 2; // Region too small (x direction)
3182 if(y2 < y1) return 3; // Region too small (y direction)
3183
3184 int bytesPerPix = (redChan<0?0:1) + (greenChan<0?0:1) + (blueChan<0?0:1) + (alphaChan<0?0:1);
3185 if(bytesPerPix < 1) return 4; // Exit if no channels selected
3186
3187 if(rasterData == 0) // Allocate space if rasterData==NULL. Caller must delete[]
3188 rasterData = (uint8_t *) new uint8_t[(y2-y1+1)*(x2-x1+1)*bytesPerPix];
3189
3190 if(rasterData == 0) return 5; // Exit if something went wrong with allocate...
3191
3192 uint8_t *curPixComp = (uint8_t *)rasterData;
3193 for(intCrdT y=y1; y<=y2; y++) {
3194 for(intCrdT x=x1; x<=x2; x++) {
3195 colorT aColor = getPxColorNC(x, y);
3196 if(redChan >= 0) curPixComp[redChan] = aColor.getChan_byte(aColor.bestRedChan());
3197 if(greenChan >= 0) curPixComp[greenChan] = aColor.getChan_byte(aColor.bestGreenChan());
3198 if(blueChan >= 0) curPixComp[blueChan] = aColor.getChan_byte(aColor.bestBlueChan());
3199 if(alphaChan >= 0) curPixComp[alphaChan] = aColor.getChan_byte(aColor.bestAlphaChan());
3200 curPixComp += bytesPerPix;
3201 } /* end for x */
3202 } /* end for y */
3203
3204 return 0;
3205 }
3206
3207////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3208 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3209 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3210 inline intCrdT
3212 if(realAxOrientationX == realAxisOrientation::NATURAL)
3213 return static_cast<intCrdT>((static_cast<fltCrdT>(x) - minRealX) / pixWidX);
3214 else
3215 return static_cast<intCrdT>((maxRealX - static_cast<fltCrdT>(x)) / pixWidX);
3216 }
3217
3218////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3219 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3220 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3221 inline intCrdT
3223 if(realAxOrientationY == realAxisOrientation::NATURAL)
3224 return static_cast<intCrdT>((static_cast<fltCrdT>(y) - minRealY) / pixWidY);
3225 else
3226 return static_cast<intCrdT>((maxRealY - static_cast<fltCrdT>(y)) / pixWidY);
3227 }
3228
3229////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3230 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3231 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3232 inline fltCrdT
3234 if(realAxOrientationX == realAxisOrientation::NATURAL)
3235 return static_cast<fltCrdT>(x) * pixWidX + minRealX;
3236 else
3237 return maxRealX - static_cast<fltCrdT>(x) * pixWidX;
3238 }
3239
3240////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3241 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3242 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3243 inline fltCrdT
3245 if(realAxOrientationY == realAxisOrientation::NATURAL)
3246 return static_cast<fltCrdT>(y) * pixWidY + minRealY;
3247 else
3248 return maxRealY - static_cast<fltCrdT>(y) * pixWidY;
3249 }
3250
3251////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3252 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3253 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3254 colorT*
3256 colorT *pixelsCopy = new colorT[numPixX * numPixY];
3257 for(intCrdT y=0; y<numPixY; y++)
3258 for(intCrdT x=0; x<numPixX; x++)
3259 pixelsCopy[numPixX * y + x] = getPxColorNC(x, y);
3260 }
3261
3262////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3263 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3264 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3265 inline colorT
3267 if(isOnCanvas(x, y)) [[likely]]
3268 return pixels[numPixX * y + x];
3269 else
3270 return colorT().setToBlack();
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 switch (interpMethod) {
3279 case interpolationType::BILINEAR : return getPxColorInterpBLin(x, y);
3280 case interpolationType::TRUNCATE : return getPxColorInterpBLin(x, y);
3281 case interpolationType::NEAREST : return getPxColorInterpBLin(x, y);
3282 case interpolationType::AVERAGE4 : return getPxColorInterpBLin(x, y);
3283 case interpolationType::AVERAGE9 : return getPxColorInterpBLin(x, y);
3284 default : return colorT("green"); // Just in case I add an enum value, and forget to update this switch.
3285 }
3286 }
3287
3288////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3289 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3290 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3291 colorT
3293 double x1 = std::floor(x);
3294 double y1 = std::floor(y);
3295 double x2 = std::ceil(x);
3296 double y2 = std::ceil(y);
3297
3298 intCrdT x1i = static_cast<intCrdT>(x1);
3299 intCrdT y1i = static_cast<intCrdT>(y1);
3300 intCrdT x2i = static_cast<intCrdT>(x2);
3301 intCrdT y2i = static_cast<intCrdT>(y2);
3302
3303 colorT cF;
3304
3305 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3306 double eps = 0.00001;
3307 double xD21 = x2 - x1;
3308 double yD21 = y2 - y1;
3309 double wH = 1.0;
3310 if (mjr::math::fc::not_near_zero(xD21, eps))
3311 wH = (x - x1) / xD21;
3312 double wV = 1.0;
3313 if (mjr::math::fc::not_near_zero(yD21, eps))
3314 wV = (y - y1) / yD21;
3315
3316 colorT c1;
3317 colorT c2;
3318 c1.linearInterpolate(wH, getPxColorRefNC(x1i, y1i), getPxColorRefNC(x2i, y1i));
3319 c2.linearInterpolate(wH, getPxColorRefNC(x1i, y2i), getPxColorRefNC(x2i, y2i));
3320 cF.linearInterpolate(wV, c1, c2);
3321 } else {
3322 cF.setToBlack();
3323 }
3324 return cF;
3325 }
3326
3327////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3328 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3329 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3330 inline colorT
3332 return getPxColor(static_cast<intCrdT>(std::trunc(x)), static_cast<intCrdT>(std::trunc(y)));
3333 }
3334
3335////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3336 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3337 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3338 inline colorT
3340 return getPxColor(static_cast<intCrdT>(std::round(x)), static_cast<intCrdT>(std::round(y)));
3341 }
3342
3343////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3344 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3345 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3346 inline colorT
3348 intCrdT xi = static_cast<intCrdT>(std::round(x));
3349 intCrdT yi = static_cast<intCrdT>(std::round(y));
3350 colorT newColor;
3351 for(int chan=0; chan<colorT::channelCount; chan++) {
3352 colorChanArithSDPType newChanValue = 0;
3353 for(intCrdT ydi=-1; ydi<=1; ydi++) {
3354 intCrdT icY = yi + ydi;
3355 for(intCrdT xdi=-1; xdi<=1; xdi++) {
3356 intCrdT icX = xi + xdi;
3357 if (!(isCliped(icX, icY))) {
3358 newChanValue += getPxColor(icX, icY).getChan(chan);
3359 }
3360 }
3361 }
3362 newColor.setChan(chan, static_cast<colorChanType>(newChanValue / 9));
3363 }
3364 return newColor;
3365 }
3366
3367////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3368 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3369 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3370 colorT
3372 double x1 = std::floor(x);
3373 double y1 = std::floor(y);
3374 double x2 = std::ceil(x);
3375 double y2 = std::ceil(y);
3376
3377 intCrdT x1i = static_cast<intCrdT>(x1);
3378 intCrdT y1i = static_cast<intCrdT>(y1);
3379 intCrdT x2i = static_cast<intCrdT>(x2);
3380 intCrdT y2i = static_cast<intCrdT>(y2);
3381
3382 if ((x1i >= 0) && (y1i >= 0) && (x2i < numPixX) && (y2i < numPixY)) {
3383
3384 colorT c1 = pixels[numPixX * y1i + x1i];
3385 c1.tfrmMean(pixels[numPixX * y1i + x2i]);
3386
3387 colorT c2 = pixels[numPixX * y2i + x1i];
3388 c2.tfrmMean(pixels[numPixX * y2i + x2i]);
3389
3390 c1.tfrmMean(c2);
3391
3392 return c1;
3393 } else {
3394 return colorT().setToBlack();
3395 }
3396 }
3397
3398// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3399// template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3400// requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3401// void
3402// ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts) {
3403// moveTo(x2, y2); // Do this first
3404// intCrdT x, y;
3405// if(y1 == y2) { // slope = 0
3406// if( (y1 < 0) || (y1 >= numPixY) ) // . Line off canvas case
3407// return;
3408// if(x1 > x2) // . Fix point ordering
3409// std::swap(x1, x2);
3410// if(x1 < 0) // . Clip left
3411// x1 = 0;
3412// if(x2 >= numPixX) // . Clip right
3413// x2 = numPixX - 1;
3414// //drawHorzLineNC(x1, x2, y1, color); // . Draw Pixels
3415// return; // mark edge
3416// } else if(x1 == x2) { // slope = infinity
3417// if( (x1 < 0) || (x1 >= numPixX) ) // . Line off canvas case
3418// return;
3419// if(y1 > y2) // . Fix point ordering
3420// std::swap(y1, y2);
3421// if(y1 < 0) // . Clip top
3422// y1 = 0;
3423// if(y2 >= numPixY) // . Clip bottom
3424// y2 = numPixY - 1;
3425// //drawVertLineNC(y1, y2, x1, color); // . Draw Pixels
3426// for(y=y1; y<=y2; y++) pts[y] = x1; // mark edge
3427// } else { // Slope is not infinity or 0...
3428// int dx, dy;
3429// if(x1 > x2) { // . Fix point ordering
3430// std::swap(x1, x2);
3431// std::swap(y1, y2);
3432// }
3433// dx = x2 - x1; // . Compute the slope
3434// dy = y2 - y1;
3435// if(dx == dy) { // . Slope = 1
3436// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // .. Line off canvas case
3437// return;
3438// if(x1 < 0) { // .. Clip left
3439// y1 = y1 - x1;
3440// x1 = 0;
3441// }
3442// if(y1 < 0) { // .. Clip top
3443// x1 = x1 - y1;
3444// y1 = 0;
3445// }
3446// if(x2 >= numPixX) { // .. Clip right
3447// y2 = y2 - (x2 - numPixX) - 1;
3448// x2 = numPixX - 1;
3449// }
3450// if(y2 >= numPixY) { // .. Clip bottom
3451// x2 = x2 - (y2 - numPixY) - 1;
3452// y2 = numPixY - 1;
3453// }
3454// for(x=x1,y=y1;x<=x2;y++,x++) // .. Draw Pixels
3455// //drawPointNC(x, y, color);
3456// pts[y] = x; // mark edge
3457// } else if(dx == -dy) { // . Slope = -1
3458// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // .. Line off canvas case
3459// return;
3460// if(x1 < 0) { // .. Clip left
3461// y1 = y1 + x1;
3462// x1 = 0;
3463// }
3464// if(x2 >= numPixX) { // .. Clip right
3465// y2 = y2 + (x2 - (numPixX - 1));
3466// x2 = numPixX - 1;
3467// }
3468// if(y2 < 0) { // .. Clip top
3469// x2 = x2 + y2;
3470// y2 = 0;
3471// }
3472// if(y1 >= numPixY) { // .. Clip bottom
3473// x1 = x1 + (y1 - (numPixY - 1));
3474// y1 = numPixY - 1;
3475// }
3476// for(x=x1,y=y1;x<=x2;y--,x++) // .. Draw Pixels
3477// //drawPointNC(x, y, color);
3478// pts[y] = x; // mark edge
3479// } else { // . Slope != 1, -1, 0, \infinity
3480// int s, dx2, dy2;
3481// dx2 = 2*dx;
3482// dy2 = 2*dy;
3483// if(dy > 0) { // .. Positive Slope
3484// if( (y2 < 0) || (x2 < 0) || (x1 >= numPixX) || (y1 >= numPixY) ) // ... Line off canvas case
3485// return;
3486// if(x1 < 0) { // ... Clip left
3487// y1 = (int)(1.0*y1-x1*dy/dx);
3488// x1 = 0;
3489// }
3490// if(y1 < 0) { // ... Clip top
3491// x1 = (int)(1.0*x1-y1*dx/dy);
3492// y1 = 0;
3493// }
3494// if(x2 >= numPixX) { // ... Clip right
3495// y2 = (int)((1.0*dy*(numPixX-1)+y1*dx-x1*dy)/dx);
3496// x2 = numPixX - 1;
3497// }
3498// if(y2 >= numPixY) { // ... Clip bottom
3499// x2 = (int)(((numPixY-1)*dx-y2*dx+x2*dy)/dy);
3500// y2 = numPixY - 1;
3501// }
3502// if(dx > dy) { // ... 0 < Slope < 1
3503// s = dy2 - dx;
3504// x=x1;
3505// y=y1;
3506// while(x<=x2) { // .... Draw Line
3507// //drawPoint(x, y, color);
3508// pts[y] = x; // mark edge
3509// if(s < 0) {
3510// s += dy2;
3511// } else {
3512// y++;
3513// s += dy2 - dx2;
3514// }
3515// x++;
3516// }
3517// } else { // ... 1 < Slope < infinity
3518// s = dy - dx2;
3519// x=x1;
3520// y=y1;
3521// while(y<=y2) { // .... Draw Line
3522// //drawPoint(x, y, color);
3523// pts[y] = x; // mark edge
3524// if(s > 0) {
3525// s -= dx2;
3526// } else {
3527// x++;
3528// s += dy2 - dx2;
3529// }
3530// y++;
3531// }
3532// }
3533// } else { // .. Negative Slope
3534// if( (x2 < 0) || (y2 >= numPixY) || (x1 >= numPixX) || (y1 < 0) ) // ... Line off canvas case
3535// return;
3536// if(x1 < 0) { // ... Clip left
3537// y1 = (int)(1.0*y1-x1*dy/dx);
3538// x1 = 0;
3539// }
3540// if(y2 < 0) { // ... Clip top
3541// x2 = (int)(1.0*x2-y2*dx/dy);
3542// y2 = 0;
3543// }
3544// if(x2 >= numPixX) { // ... Clip right
3545// y2 = (int)((1.0*dy*(numPixX-1)+y2*dx-x2*dy)/dx);
3546// x2 = numPixX - 1;
3547// }
3548// if(y1 >= numPixY) { // ... Clip bottom
3549// x1 = (int)(((numPixY-1)*dx-y1*dx+x1*dy)/dy);
3550// y1 = numPixY - 1;
3551// }
3552// if(dx > -dy) { // ... 0 > Slope > -infinity
3553// s = dy2 + dx;
3554// x=x1;
3555// y=y1;
3556// while(x<=x2) { // .... Draw Line
3557// //drawPoint(x, y, color);
3558// pts[y] = x; // mark edge
3559// if(s > 0) {
3560// s += dy2;
3561// } else {
3562// y--;
3563// s += dy2 + dx2;
3564// }
3565// x++;
3566// }
3567// } else { // ... -1 > Slope > -inf
3568// s = dy + dx2;
3569// x=x1;
3570// y=y1;
3571// while(y>=y2) { // .... Draw Line
3572// //drawPoint(x, y, color);
3573// pts[y] = x; // mark edge
3574// if(s < 0) {
3575// s += dx2;
3576// } else {
3577// x++;
3578// s += dy2 + dx2;
3579// }
3580// y--;
3581// }
3582// }
3583// }
3584// }
3585// }
3586// }
3587
3588////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3589 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3590 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3591 inline void
3592 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::triangleEdger(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT* pts, bool findMin) {
3593 // This code is essentially the line drawing code with some simplifications.
3594 intCrdT x, y;
3595 if(x1 == x2) { // slope = infinity
3596 if(y1 > y2) // Fix point ordering
3597 std::swap(y1, y2);
3598 for(y=y1; y<=y2; y++) // Draw PIxels: drawVertLineNC(y1, y2, x1, color);
3599 pts[y]=x1; // set bound
3600 } else { // Slope is not infinity or 0...
3601 int dx, dy;
3602 if(x1 > x2) { // Fix point ordering
3603 std::swap(x1, x2);
3604 std::swap(y1, y2);
3605 }
3606 dx = x2 - x1; // Compute the slope
3607 dy = y2 - y1;
3608 if(dx == dy) { // Slope = 1
3609 for(x=x1,y=y1;x<=x2;y++,x++) // Draw Pixels
3610 pts[y]=x; // set bound
3611 } else if(dx == -dy) { // Slope = -1
3612 for(x=x1,y=y1;x<=x2;y--,x++) // Draw Pixels
3613 pts[y]=x; // set bound
3614 } else { // Slope != 1, -1, 0, \infinity
3615 int s, dx2, dy2;
3616 dx2 = 2*dx;
3617 dy2 = 2*dy;
3618 if(dy > 0) { // Positive Slope
3619 if(dx > dy) { // 0 < Slope < 1
3620 if (findMin) {
3621 s = dy2 - dx;
3622 x=x1;
3623 y=y1;
3624 intCrdT lastY=y-1;
3625 while(x<=x2) { // Draw Line
3626 if (y != lastY)
3627 pts[y]=x; // set bound
3628 lastY = y;
3629 if(s < 0) {
3630 s += dy2;
3631 } else {
3632 y++;
3633 s += dy2 - dx2;
3634 }
3635 x++;
3636 }
3637 } else { // works.
3638 s = dy2 - dx;
3639 x=x1;
3640 y=y1;
3641 while(x<=x2) { // Draw Line
3642 pts[y]=x; // set bound
3643 if(s < 0) {
3644 s += dy2;
3645 } else {
3646 y++;
3647 s += dy2 - dx2;
3648 }
3649 x++;
3650 }
3651 }
3652 } else { // 1 < Slope < infinity
3653 s = dy - dx2;
3654 x=x1;
3655 y=y1;
3656 while(y<=y2) { // Draw Line
3657 pts[y]=x; // set bound
3658 if(s > 0) {
3659 s -= dx2;
3660 } else {
3661 x++;
3662 s += dy2 - dx2;
3663 }
3664 y++;
3665 }
3666 }
3667 } else { // Negative Slope
3668 if(dx > -dy) { // 0 > Slope > -1
3669 if (findMin) {
3670 s = dy2 + dx;
3671 x=x1;
3672 y=y1;
3673 intCrdT lastY=y-1;
3674 while(x<=x2) { // Draw Line
3675 if (y != lastY)
3676 pts[y]=x; // set bound
3677 lastY = y;
3678 if(s > 0) {
3679 s += dy2;
3680 } else {
3681 y--;
3682 s += dy2 + dx2;
3683 }
3684 x++;
3685 }
3686 } else {
3687 s = dy2 + dx;
3688 x=x1;
3689 y=y1;
3690 while(x<=x2) { // Draw Line
3691 pts[y]=x; // set bound
3692 if(s > 0) {
3693 s += dy2;
3694 } else {
3695 y--;
3696 s += dy2 + dx2;
3697 }
3698 x++;
3699 }
3700 }
3701 } else { // -1 > Slope > -inf
3702 s = dy + dx2;
3703 x=x1;
3704 y=y1;
3705 while(y>=y2) { // Draw Line
3706 pts[y]=x; // set bound
3707 if(s < 0) {
3708 s += dx2;
3709 } else {
3710 x++;
3711 s += dy2 + dx2;
3712 }
3713 y--;
3714 }
3715 }
3716 }
3717 }
3718 }
3719 }
3720
3721////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3722 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3723 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3724 inline void
3725 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3726 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color, color, color, true);
3727 }
3728
3729////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3730 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3731 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3732 inline void
3734 intCrdT x2, intCrdT y2,
3735 intCrdT x3, intCrdT y3,
3736 colorArgType color1, colorArgType color2, colorArgType color3) {
3737 drawFillTriangleUtl(x1, y1, x2, y2, x3, y3, color1, color2, color3, false);
3738 }
3739
3740////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3741 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3742 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3743 void
3745 intCrdT x2, intCrdT y2,
3746 intCrdT x3, intCrdT y3,
3747 colorT c1, colorT c2, colorT c3, bool solid) { // Not colorArgType because of std::swap
3748 static intCrdT *minPts, *maxPts;
3749 static intCrdT numPts;
3750
3751 if( isCliped(x1, y1) || isCliped(x2, y2) || isCliped(x3, y3))
3752 return;
3753
3754 ///////////////////////////////////////////////////////////////////////////////////
3755 // Check our work space, and allocate/reallocate as required.
3756 if(minPts == NULL) { // First time in function -- allocate
3757 minPts = new intCrdT[numPixY];
3758 maxPts = new intCrdT[numPixY];
3759 numPts = numPixY;
3760 } else { // Not our first time! We have a work space.
3761 if(numPts != numPixY) { // Work space is wrong size -- reallocate
3762 delete[] minPts;
3763 delete[] maxPts;
3764 minPts = new intCrdT[numPixY];
3765 maxPts = new intCrdT[numPixY];
3766 numPts = numPixY;
3767 }
3768 }
3769
3770 ///////////////////////////////////////////////////////////////////////////////////
3771 if (!(solid) && ((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) == 0))
3772 return;
3773
3774 ///////////////////////////////////////////////////////////////////////////////////
3775 // Sort (x1,y1), (x2,y2), (x3,y3) so that y1 >= y2, y3 and y3 <= y2, y1
3776 if(y1 > y2) { // top != 2 && bot != 1
3777 if(y1 > y3) { // top != 3 y1>y2 y1>y3 y2>y3 top bot
3778 if(y2 > y3) { // bot != 2 . . . . .
3779 // T T T 1 3 NOP
3780 } else { // bot != 3 . . . . .
3781 std::swap(y2,y3); // T T F 1 2 SWAP(2,3)
3782 std::swap(x2,x3); // . . . . .
3783 std::swap(c2,c3); // . . . . .
3784 } // . . . . .
3785 } else { // top != 1 . . . . .
3786 std::swap(y1,y3); // T F U 3 2 SWAP(1,3) SWAP(2,3)
3787 std::swap(y2,y3); // . . . . .
3788 std::swap(x1,x3); // . . . . .
3789 std::swap(x2,x3); // . . . . .
3790 if(!solid) { // . . . . .
3791 std::swap(c1,c3); // . . . . .
3792 std::swap(c2,c3); // . . . . .
3793 } // . . . . .
3794 } // . . . . .
3795 } else { // top != 1 . . . . .
3796 if(y2 > y3) { // top != 3 && bot != 2 . . . . .
3797 if(y1 > y3) { // bot != 1 . . . . .
3798 std::swap(y1,y2); // F T T 2 3 SWAP(1,2)
3799 std::swap(x1,x2); // . . . . .
3800 std::swap(c1,c2); // . . . . .
3801 } else { // bot != 3 . . . . .
3802 std::swap(y1,y2); // F F T 2 1 SWAP(1,2) SWAP(2,3)
3803 std::swap(y2,y3); // . . . . .
3804 std::swap(x1,x2); // . . . . .
3805 std::swap(x2,x3); // . . . . .
3806 if(!solid) { // . . . . .
3807 std::swap(c1,c2); // . . . . .
3808 std::swap(c2,c3); // . . . . .
3809 } // . . . . .
3810 } // . . . . .
3811 } else { // top != 2 && bot != 3 . . . . .
3812 std::swap(y1,y3); // F U F 3 1 SWAP(1,3)
3813 std::swap(x1,x3); // . . . . .
3814 std::swap(c1,c3); // . . . . .
3815 }
3816 }
3817
3818 ///////////////////////////////////////////////////////////////////////////////////////
3819 /* cA y1==y2 point 1,2,3 */
3820 /* cB-cG y1==y2 h line 1,2---3 3---1,2 1,3---2 2---1,3 2,3---1 1---2,3 */
3821 /* cH-cJ y1==y2 v line 1,2 1,2 1,2 */
3822 /* \ | / */
3823 /* 3 3 3 */
3824 /* cK-cL y1==y2 tri 1---2 2---1 */
3825 /* \ / \ / */
3826 /* 3 3 */
3827 /* cM-cO y2=y3 v line 1 1 1 */
3828 /* \ | / */
3829 /* 2,3 2,3 2,3 */
3830 /* cP-cQ y2=y3 tri 1 1 */
3831 /* / \ / \ */
3832 /* 2---3 3---2 */
3833 /* cR-cS General 1 1 Note x1 need not equal x3 in these cases! */
3834 /* |\ /| It is just difficult to draw a case with */
3835 /* | 2 2 | x1 != x3 with tiny ASCII art... */
3836 /* |/ \| */
3837 /* 3 3 */
3838 ///////////////////////////////////////////////////////////////////////////////////////
3839
3840 if(y1==y3) { // cA-cG
3841 minPts[y1] = mjr::math::odr::min3(x1, x2, x3); //
3842 maxPts[y1] = mjr::math::odr::max3(x1, x2, x3); //
3843 } else { // cH-cS
3844 if(y1==y2) { // cH-cL
3845 if(x1==x2) { // cH-cJ
3846 triangleEdger(x1, y1, x3, y3, minPts, true); //
3847 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3848 } else if(x1<x2) { // cK
3849 triangleEdger(x1, y1, x3, y3, minPts, true); //
3850 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3851 } else { // cJ
3852 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3853 triangleEdger(x2, y2, x3, y3, minPts, true); //
3854 } //
3855 } else if(y2==y3) { // cM-cQ
3856 if(x2==x3) { // cM-cO
3857 triangleEdger(x1, y1, x3, y3, minPts, true); //
3858 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3859 } else if(x2<x3) { // cP
3860 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3861 triangleEdger(x2, y2, x1, y1, minPts, true); //
3862 } else { // cQ
3863 triangleEdger(x1, y1, x3, y3, minPts, true); //
3864 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3865 } //
3866 } else { // cR-cS
3867 double xOt = (x1*y3+x3*y2-x1*y2-x3*y1); //
3868 double xOb = (y3-y1); //
3869 if(xOt/xOb < x2) { // cR
3870 triangleEdger(x1, y1, x3, y3, minPts, true); //
3871 triangleEdger(x2, y2, x1, y1, maxPts, false); //
3872 triangleEdger(x2, y2, x3, y3, maxPts, false); //
3873 } else { // cS
3874 triangleEdger(x1, y1, x3, y3, maxPts, false); //
3875 triangleEdger(x2, y2, x1, y1, minPts, true); //
3876 triangleEdger(x2, y2, x3, y3, minPts, true); //
3877 } //
3878 } //
3879 } //
3880
3881 ///////////////////////////////////////////////////////////////////////////////////
3882 // Fill between the left and right bits.
3883 if(solid) {
3884 for(intCrdT y=y3; y<=y1; y++)
3885 drawLine(minPts[y], y, maxPts[y], y, c1);
3886 } else {
3887 for(intCrdT y=y3; y<=y1; y++)
3888 for(intCrdT x=minPts[y]; x<=maxPts[y]; x++) {
3889 /* Performance & Correctness: This code seems very poorly optimized. Especially the computation of w3 instead of simply using 1-w1-w2, and the
3890 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
3891 computations. Sometimes, for example, the coordinates of a fill point won't, technically, be in the triangle. Or the sum of the areas
3892 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
3893 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
3894 consistency and accuracy on edges. The repeated common expressions are optimized by the compiler. This branch is roughly 15x slower than the
3895 solid branch above. */
3896 colorChanArithFltType w1 = std::abs(static_cast<colorChanArithFltType>( x*(y2 - y3) + x2*(y3 - y) + x3*(y - y2)));
3897 colorChanArithFltType w2 = std::abs(static_cast<colorChanArithFltType>(x1*(y - y3) + x*(y3 - y1) + x3*(y1 - y)));
3898 colorChanArithFltType w3 = std::abs(static_cast<colorChanArithFltType>(x1*(y2 - y) + x2*(y - y1) + x*(y1 - y2)));
3899 drawPointNC(x, y, colorT().wMean(w1/(w1+w2+w3), w2/(w1+w2+w3), w3/(w1+w2+w3), c1, c2, c3));
3900 }
3901 }
3902 }
3903
3904////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3905 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3906 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3907 inline void
3909 drawPLCurve(numPoints, x, y, dfltColor);
3910 }
3911
3912////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3913 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3914 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3915 inline void
3917 for(int i=0; i<numPoints-1; i++)
3918 drawLine(real2intX(x[i]), real2intY(y[i]), real2intX(x[i+1]), real2intY(y[i+1]), color);
3919 }
3920
3921////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3922 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3923 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3924 inline void
3926 drawPLCurve(numPoints, x, y, dfltColor);
3927 }
3928
3929////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3930 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3931 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3932 inline void
3934 for(int i=0; i<numPoints-1; i++)
3935 drawLine(x[i], y[i], x[i+1], y[i+1], color);
3936 }
3937
3938////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3939 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3940 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3941 inline void
3943 for(int i=0; i<numPoints-1; i++)
3944 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3945 }
3946
3947////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3948 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3949 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3950 inline void
3952 for(int i=0; i<numPoints-1; i++)
3953 drawLine(thePoints[i].x, thePoints[i].y, thePoints[i+1].x, thePoints[i+1].y, color);
3954 }
3955
3956////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3957 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3958 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3959 inline void
3961 drawPLCurve(numPoints, thePoints, dfltColor);
3962 }
3963
3964////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3965 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3966 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3967 inline void
3969 drawPLCurve(numPoints, thePoints, dfltColor);
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 inline void
3976 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawTriangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, intCrdT x3, intCrdT y3, colorArgType color) {
3977 drawLine(x1, y1, x2, y2, color);
3978 drawLine(x2, y2, x3, y3, color);
3979 drawLine(x3, y3, x1, y1, color);
3980 }
3981
3982////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3983 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
3984 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
3985 void
3986 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
3987 int x = 0;
3988 int y = radiusX;
3989 int d = 1 - radiusX;
3990 int deltaE = 3;
3991 int deltaSE = -2 * radiusX + 5;
3992
3993 drawPoint( x+centerX, y+centerY, color);
3994 drawPoint( x+centerX,-y+centerY, color);
3995 drawPoint(-x+centerX, y+centerY, color);
3996 drawPoint(-x+centerX,-y+centerY, color);
3997 drawPoint( y+centerX, x+centerY, color);
3998 drawPoint( y+centerX,-x+centerY, color);
3999 drawPoint(-y+centerX, x+centerY, color);
4000 drawPoint(-y+centerX,-x+centerY, color);
4001
4002 while(y>x) {
4003 if(d<0) {
4004 d += deltaE;
4005 deltaE += 2;
4006 deltaSE += 2;
4007 } else {
4008 d += deltaSE;
4009 deltaE += 2;
4010 deltaSE += 4;
4011 y--;
4012 }
4013 x++;
4014 drawPoint( x+centerX, y+centerY, color);
4015 drawPoint( x+centerX,-y+centerY, color);
4016 drawPoint(-x+centerX, y+centerY, color);
4017 drawPoint(-x+centerX,-y+centerY, color);
4018 drawPoint( y+centerX, x+centerY, color);
4019 drawPoint( y+centerX,-x+centerY, color);
4020 drawPoint(-y+centerX, x+centerY, color);
4021 drawPoint(-y+centerX,-x+centerY, color);
4022 }
4023
4024 }
4025
4026////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4027 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4028 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4029 void
4030 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawFillCircle(intCrdT centerX, intCrdT centerY, intCrdT radiusX, colorArgType color) {
4031 int minXY;
4032 int x = 0;
4033 int y = radiusX;
4034 int d = 1 - radiusX;
4035 int deltaE = 3;
4036 int deltaSE = -2 * radiusX + 5;
4037
4038 if(x > y)
4039 minXY = y;
4040 else
4041 minXY = x;
4042 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
4043 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
4044 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
4045 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
4046 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
4047 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
4048 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4049 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4050
4051 while(y>x) {
4052 if(d<0) {
4053 d += deltaE;
4054 deltaE += 2;
4055 deltaSE += 2;
4056 } else {
4057 d += deltaSE;
4058 deltaE += 2;
4059 deltaSE += 4;
4060 y--;
4061 }
4062 x++;
4063
4064 if(x > y)
4065 minXY = y;
4066 else
4067 minXY = x;
4068 drawLine( x+centerX, y+centerY, x+centerX, minXY+centerY, color);
4069 drawLine( -x+centerX, y+centerY, -x+centerX, minXY+centerY, color);
4070 drawLine( x+centerX, -y+centerY, x+centerX, -minXY+centerY, color);
4071 drawLine( -x+centerX, -y+centerY, -x+centerX, -minXY+centerY, color);
4072 drawLine( y+centerX, x+centerY, minXY+centerX, x+centerY, color);
4073 drawLine( y+centerX, -x+centerY, minXY+centerX, -x+centerY, color);
4074 drawLine( -y+centerX, x+centerY, -minXY+centerX, x+centerY, color);
4075 drawLine( -y+centerX, -x+centerY, -minXY+centerX, -x+centerY, color);
4076 }
4077 }
4078
4079////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4080 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4081 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4082 void
4083 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawRectangle(intCrdT x1, intCrdT y1, intCrdT x2, intCrdT y2, colorArgType color) {
4084 if(x1 > x2) // Get x1 < x2
4085 std::swap(x1, x2);
4086 if(y1 > y2) // Get y1 < y2
4087 std::swap(y1, y2);
4088 if( (y1 < numPixY) && (x1 < numPixX) && (y2 >= 0) && (x2 >= 0) ) { // Part of rect visible
4089 int noTop, noBottom, noLeft, noRight;
4090 if((noTop=(y1 < 0)))
4091 y1 = 0;
4092 if((noLeft=(x1 < 0)))
4093 x1 = 0;
4094 if((noBottom=(y2 >= numPixY)))
4095 y2 = numPixY - 1;
4096 if((noRight=(x2 >= numPixX)))
4097 x2 = numPixX - 1;
4098 // Draw top/bottom/left/right lines
4099 if(!noLeft) // Have left
4100 drawVertLineNC(y1, y2, x1, color);
4101 if(!noRight) // Have Right
4102 drawVertLineNC(y1, y2, x2, color);
4103 if(!noTop) // Have top
4104 drawHorzLineNC(x1, x2, y1, color);
4105 if(!noBottom) // Have bottom
4106 drawHorzLineNC(x1, x2, y2, color);
4107 }
4108 }
4109
4110////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4111 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4112 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4113 inline void
4115 if(x1 > x2) // Get x1 < x2
4116 std::swap(x1, x2);
4117 if(y1 > y2) // Get y1 < y2
4118 std::swap(y1, y2);
4119 // Clip
4120 if( (y1 >= numPixY) || (x1 >= numPixX) || (y2 < 0) || (x2 < 0) )
4121 return;
4122 if(y1 < 0)
4123 y1 = 0;
4124 if(x1 < 0)
4125 x1 = 0;
4126 if(y2 >= numPixY)
4127 y2 = numPixY - 1;
4128 if(x2 >= numPixX)
4129 x2 = numPixX - 1;
4130 for(intCrdT y=y1;y<=y2;y++)
4131 drawHorzLineNC(x1, x2, y, color);
4132 }
4133
4134////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4135 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4136 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4137 inline void
4139 if constexpr (enableDrawModes)
4140 switch(drawMode) {
4141 case drawModeType::SET: getPxColorRefNC(x, y).copy(color); break;
4142 case drawModeType::XOR: getPxColorRefNC(x, y).tfrmXor(color); break;
4143 case drawModeType::ADDCLAMP: getPxColorRefNC(x, y).tfrmAddClamp(color); break;
4144 case drawModeType::AND: getPxColorRefNC(x, y).tfrmAnd(color); break;
4145 case drawModeType::OR: getPxColorRefNC(x, y).tfrmOr(color); break;
4146 case drawModeType::DIFFCLAMP: getPxColorRefNC(x, y).tfrmDiffClamp(color); break;
4147 case drawModeType::MULTCLAMP: getPxColorRefNC(x, y).tfrmMultClamp(color); break;
4148 }
4149 else
4150 getPxColorRefNC(x, y).copy(color);
4151 }
4152
4153////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4154 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4155 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4156 void
4158 if (xfactor > 1) {
4159 intCrdT new_numPixX_p = xfactor*numPixX;
4160 intCrdT new_numPixY_p = xfactor*numPixY;
4161 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4162 for(intCrdT y=0, y1=0; y<numPixY; y++) {
4163 for(intCrdT x=0, x1=0; x<numPixX; x++) {
4164 for(int i=0; i<xfactor; i++) {
4165 for(int j=0; j<xfactor; j++) {
4166 new_pixels[new_numPixX_p * y1 + x1] = getPxColor(x, y);
4167 x1++;
4168 }
4169 x1-=xfactor;
4170 y1++;
4171 }
4172 x1+=xfactor;
4173 y1-=xfactor;
4174 }
4175 y1+=xfactor;
4176 }
4177 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4178 }
4179 }
4180
4181////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4182 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4183 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4184 void
4186 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4187 intCrdT new_numPixX_p = numPixX/xfactor;
4188 intCrdT new_numPixY_p = numPixY/xfactor;
4189 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4190 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4191 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor)
4192 new_pixels[new_numPixX_p * y + x] = getPxColor(x1, y1);
4193 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4194 }
4195 }
4196
4197////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4198 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4199 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4200 void
4202 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4203 intCrdT new_numPixX_p = numPixX/xfactor;
4204 intCrdT new_numPixY_p = numPixY/xfactor;
4205 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4206 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4207 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4208 std::vector<colorChanArithSDPType> sums(colorT::channelCount, static_cast<colorChanArithSDPType>(0));
4209 for(int j=0; j<xfactor; j++)
4210 for(int i=0; i<xfactor; i++)
4211 for(int c=0; c<colorT::channelCount; c++)
4212 sums[c] += getPxColor(x1+i, y1+j).getChan(c);
4213 colorT aColor;
4214 for(int c=0; c<colorT::channelCount; c++)
4215 aColor.setChan(c, static_cast<colorChanType>(sums[c] / (xfactor*xfactor)));
4216 new_pixels[new_numPixX_p * y + x] = aColor;
4217 }
4218 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4219 }
4220 }
4221
4222////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4223 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4224 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4225 void
4227 if ((xfactor > 1) && (xfactor <= numPixX) && (xfactor <= numPixY)) {
4228 intCrdT new_numPixX_p = numPixX/xfactor;
4229 intCrdT new_numPixY_p = numPixY/xfactor;
4230 colorT *new_pixels = new colorT[new_numPixX_p * new_numPixY_p];
4231 for(intCrdT y=0, y1=0; y<new_numPixY_p; y++, y1+=xfactor)
4232 for(intCrdT x=0, x1=0; x<new_numPixX_p; x++, x1+=xfactor) {
4233 colorT maxColor = getPxColor(xfactor*x, xfactor*y);
4234 for(int yi=0; yi<xfactor; yi++)
4235 for(int xi=0; xi<xfactor; xi++)
4236 maxColor.tfrmMaxI(getPxColor(xfactor*x+xi, xfactor*y+yi));
4237 new_pixels[new_numPixX_p * y + x] = maxColor;
4238 }
4239 rePointPixels(new_pixels, new_numPixX_p, new_numPixY_p);
4240 }
4241 }
4242
4243////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4244 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4245 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4246 void
4248 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4249 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4250 kernel[kSize * yi + xi] = exp(-(xis*xis+yis*yis)/(2*sd*sd))/(sd*sd*2*std::numbers::pi);
4251 double divisor = 0;
4252 for(int i=0; i<(kSize*kSize); i++)
4253 divisor += kernel[i];
4254 for(int i=0; i<(kSize*kSize); i++)
4255 kernel[i] /= divisor;
4256 }
4257
4258////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4259 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4260 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4261 void
4263 for(int yi=0, yis=-(kSize/2); yi<kSize; yi++, yis++)
4264 for(int xi=0,xis=-(kSize/2); xi<kSize; xi++, xis++)
4265 kernel[kSize * yi + xi] = 1.0/(kSize*kSize);
4266 }
4267
4268////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4269 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4270 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4271 void
4272 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::convolution(double *kernel, int kWide, int kTall, double divisor) {
4273 colorT *new_pixels = new colorT[numPixX * numPixY];
4274 // Divisor is invalid, so we compute one to use
4275 if (mjr::math::fc::near_zero(divisor, 0.0001)) {
4276 divisor = 0.0;
4277 for(int i=0; i<(kWide*kTall); i++)
4278 divisor += kernel[i];
4279 }
4280 // Apply filter
4281 double tmp[colorT::channelCount];
4282 for(intCrdT y=0; y<numPixY; y++) {
4283 for(intCrdT x=0; x<numPixX; x++) {
4284 colorT newColor;
4285 for(int chan=0; chan<colorT::channelCount; chan++)
4286 tmp[chan] = 0.0;
4287 for(int yi=0, yis=-(kTall/2); yi<kTall; yi++, yis++) {
4288 intCrdT icY = y + yis;
4289 for(int xi=0,xis=-(kWide/2); xi<kWide; xi++, xis++) {
4290 intCrdT icX = x + xis;
4291 if (!(isCliped(icX, icY))) {
4292 for(int chan=0; chan<colorT::channelCount; chan++)
4293 tmp[chan] += static_cast<double>(getPxColor(icX, icY).getChan(chan)) * kernel[kWide * yi + xi];
4294 }
4295 }
4296 }
4297 for(int chan=0; chan<colorT::channelCount; chan++)
4298 new_pixels[numPixX * y + x].setChan(chan, static_cast<colorChanType>(tmp[chan] / divisor));
4299 }
4300 }
4301 rePointPixels(new_pixels, numPixX, numPixY);
4302 }
4303
4304////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4305 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4306 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4307 inline void
4309 convolution(kernel, kSize, kSize, divisor);
4310 }
4311////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4312 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4313 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4314 inline void
4316 convolution(kernel, kSize, kSize, 1.0);
4317 }
4318
4319////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4320 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4321 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4322 void
4323 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawHersheyGlyph(int glyphNum, intCrdT x, intCrdT y, double magX, double magY, colorArgType aColor) {
4324 intCrdT x1, y1;
4325 int actionIsMoveTo;
4326
4327 if( (glyphNum < 0) || (glyphNum > 3934) )
4328 glyphNum = 699;
4329
4330 actionIsMoveTo=1;
4331 for(int i=0; i<(mjr::hershey::chars[glyphNum]).numComp; i++) {
4332 if((mjr::hershey::chars[glyphNum]).components[2*i] == ' ') {
4333 actionIsMoveTo = 1;
4334 } else {
4335 if(isIntAxOrientationNaturalX())
4336 x1 = static_cast<intCrdT>(magX * ((mjr::hershey::chars[glyphNum]).components[2*i] - 'R'));
4337 else
4338 x1 = static_cast<intCrdT>(magX * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i]));
4339
4340 if(isIntAxOrientationNaturalY())
4341 y1 = static_cast<intCrdT>(magY * ('R' - (mjr::hershey::chars[glyphNum]).components[2*i+1]));
4342 else
4343 y1 = static_cast<intCrdT>(magY * ((mjr::hershey::chars[glyphNum]).components[2*i+1] - 'R'));
4344
4345 if(actionIsMoveTo) {
4346 moveTo(x1+x, y1+y);
4347 actionIsMoveTo = 0;
4348 } else {
4349 drawLine(x1+x, y1+y, aColor);
4350 }
4351 }
4352 }
4353 }
4354
4355////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4356 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4357 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4358 inline void
4359 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes>::drawString(std::string aString, mjr::hershey::font aFont, intCrdT x, intCrdT y, colorArgType aColor, double cex, intCrdT spc) {
4360 for(auto &c : aString) {
4361 int glyphNum = 0;
4362 if((c>=32) && (c<=126))
4363 glyphNum = mjr::hershey::ascii2hershey[(int)aFont][c-32];
4364 drawHersheyGlyph(glyphNum, x, y, cex, cex, aColor);
4365 x+=static_cast<intCrdT>(spc*cex);
4366 }
4367 }
4368
4369////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4370 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4371 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4372 inline void
4374 mjr::hershey::font aFont,
4375 intCrdT x, intCrdT y,
4376 colorArgType stringColor, colorArgType boxColor,
4377 double cex, intCrdT spc) {
4378 drawFillRectangle(static_cast<intCrdT>(x-spc*cex),
4379 static_cast<intCrdT>(y-spc*cex),
4380 static_cast<intCrdT>(x+spc*cex*static_cast<int>(aString.length())),
4381 static_cast<intCrdT>(y+spc*cex),
4382 boxColor);
4383 drawString(aString, aFont, x, y, stringColor, cex, spc);
4384 }
4385
4386////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4387 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4388 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4389 int
4391 char strBuf[256];
4392
4393 std::ifstream iStream(fileName, std::ios_base::binary);
4394
4395 if (!(iStream.good()))
4396 return 1;
4397
4398 iStream.getline(strBuf, 10, '\n');
4399 if (!(iStream.good()))
4400 return 11;
4401 if (iStream.gcount() != 7)
4402 return 24;
4403 if(std::string(strBuf) != std::string("MJRRAW"))
4404 return 24;
4405
4406 int fileWide = -1;
4407 int fileTall = -1;
4408 int fileChans = -1;
4409 int fileBitPerChan = -1;
4410 bool fileIsSGN = true, fileHasS = false;
4411 bool fileIsInt = true, fileHasT = false;
4412 bool fileIsLTL = true, fileHasI = false;
4413
4414 iStream.getline(strBuf, 100, '\n');
4415 if (!(iStream.good()))
4416 return 11;
4417 if (iStream.gcount() != 93)
4418 return 26;
4419
4420 std::string::size_type tagIdx;
4421 std::string::size_type prcIdx = 0;
4422 std::string strBufS(strBuf);
4423 std::string delChrs("abcdefghijklmnopqrstuvwxyz");
4424 int stoiErrorCount = 0;
4425
4426 while(true) {
4427 tagIdx = strBufS.find_first_of(delChrs, prcIdx);
4428 if (tagIdx == std::string::npos)
4429 break;
4430 // std::cout << "suc: " << strBufS.substr(prcIdx) << std::endl;
4431 // std::cout << "tok: " << strBufS.substr(prcIdx, tagIdx-prcIdx) << std::endl;
4432 try {
4433 switch(strBufS[tagIdx]) {
4434 case 'x' : fileWide = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4435 case 'y' : fileTall = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4436 case 'c' : fileChans = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4437 case 'b' : fileBitPerChan = std::stoi(strBufS.substr(prcIdx, tagIdx-prcIdx)); break;
4438 case 's' : fileIsSGN = (strBufS[prcIdx] == 'S'); fileHasS = true; break;
4439 case 't' : fileIsInt = (strBufS[prcIdx] == 'I'); fileHasT = true; break;
4440 case 'i' : fileIsLTL = (strBufS[prcIdx] == 'L'); fileHasI = true; break;
4441 }
4442 } catch (...) {
4443 stoiErrorCount++;
4444 }
4445 prcIdx=tagIdx+1;
4446 }
4447
4448 int fileBytePerChan = fileBitPerChan / 8;
4449
4450 // std::cout << "fileWide " << fileWide << std::endl;
4451 // std::cout << "fileTall " << fileTall << std::endl;
4452 // std::cout << "fileChans " << fileChans << std::endl;
4453 // std::cout << "fileBitPerChan " << fileBitPerChan << std::endl;
4454 // std::cout << "fileIsSGN " << fileIsSGN << std::endl;
4455 // std::cout << "fileIsInt " << fileIsInt << std::endl;
4456 // std::cout << "fileIsLTL " << fileIsLTL << std::endl;
4457 // std::cout << "fileBytePerChan: " << fileBytePerChan << std::endl;
4458
4459 if (stoiErrorCount > 0)
4460 return 29;
4461
4462 if (fileWide < 0)
4463 return 33;
4464 if (fileTall < 0)
4465 return 34;
4466 if (fileChans < 0)
4467 return 35;
4468 if (fileBitPerChan < 0)
4469 return 36;
4470
4471 if (fileWide == 0)
4472 return 8;
4473 if (fileTall == 0)
4474 return 9;
4475
4476 if (fileWide > intCrdMax)
4477 return 27;
4478 if (fileTall > intCrdMax)
4479 return 28;
4480
4481 resizeCanvas(fileWide, fileTall);
4482
4483 if (fileWide != numPixX)
4484 return(12);
4485 if (fileTall != numPixY)
4486 return(14);
4487
4488 if (!(fileHasT))
4489 fileIsInt = true;
4490
4491 if (!(fileHasS))
4492 fileIsSGN = ( !(fileIsInt)); // If file is missing 's', then assume it's compatable with 't'
4493
4494 if ((colorT::chanIsInt && fileIsSGN))
4495 return 23;
4496
4497 if ((colorT::chanIsInt && !fileIsInt) ||
4498 (colorT::chanIsFloat && fileIsInt))
4499 return 21;
4500
4501 if(fileChans != colorT::channelCount)
4502 return 19;
4503
4504 if(fileBitPerChan != colorT::bitsPerChan)
4505 return 20;
4506
4507 if (!(fileHasI))
4508 fileIsLTL = (platformEndianness() == endianType::LITTLE); // missing 'i', then assume LITTLE.
4509
4510 bool reverseBits = (( fileIsLTL && (platformEndianness() == endianType::BIG)) ||
4511 (!(fileIsLTL) && (platformEndianness() == endianType::LITTLE)));
4512
4513 intCrdT x, y;
4514 bool yNat = !(isIntAxOrientationNaturalY());
4515 bool xNat = isIntAxOrientationNaturalX();
4516 for((yNat?y=0:y=(numPixY-1)); (yNat?y<numPixY:y>=0); (yNat?y++:y--)) {
4517 for((xNat?x=0:x=(numPixX-1)); (xNat?x<numPixX:x>=0); (xNat?x++:x--)) {
4518 for(int ci=0; ci<fileChans; ci++) {
4519 if constexpr (colorT::chanIsInt) {
4520 colorChanArithLogType shft = (reverseBits ? colorT::bitsPerChan-8 : 0);
4521 /* Note that colorChanArithLogType is always an unsigned integer type, and thus we avoid compiler errors when trying to use | on a float.
4522 When chanIsInt, colorChanArithLogType is the same as colorChanType when chanIsInt -- so a NOOP because this part of the if only gets
4523 run when chanIsInt. */
4524 colorChanArithLogType pv = 0;
4525 for(int bi=0; bi<fileBytePerChan; bi++) {
4526 colorChanArithLogType uch = (unsigned char)iStream.get();
4527 if (!(iStream.good()))
4528 return 25;
4529 if (iStream.gcount() != 1)
4530 return 25;
4531 pv = pv | static_cast<colorChanArithLogType>(uch << shft);
4532
4533 if (reverseBits)
4534 shft -= 8;
4535 else
4536 shft += 8;
4537 }
4538 getPxColorRefNC(x, y).setChan(ci, static_cast<colorChanType>(pv));
4539 } else {
4540 iStream.read(strBuf, fileBytePerChan);
4541 getPxColorRefNC(x, y).setChan(ci, *((colorChanType*)strBuf));
4542 }
4543 }
4544 }
4545 }
4546 iStream.close();
4547 return 0;
4548 }
4549
4550////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4551 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4552 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4553 int
4555#ifndef MRASTER_FOUND_TIFF
4556 std::cerr << "ERROR: libTIFF no supported: readTIFFfile can't read " << fileName << std::endl;
4557 return 32;
4558#else
4559 TIFF* tif;
4560 uint32_t wTIFF, hTIFF;
4561 uint16_t pmTIFF, pcTIFF, sppTIFF, bpsTIFF, fmtTIFF;
4562
4563 // Open our tiff image
4564 if( !(tif = TIFFOpen(fileName.c_str(), "r")))
4565 return 1;
4566
4567 if(TIFFIsTiled(tif))
4568 return 23;
4569
4570 // All these tags are required -- bail if any are missing.
4571 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &wTIFF))
4572 return 2;
4573 if( 1 != TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hTIFF))
4574 return 3;
4575 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &sppTIFF))
4576 return 4;
4577 if( 1 != TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &pcTIFF))
4578 return 5;
4579 if( 1 != TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &pmTIFF))
4580 return 6;
4581 if( 1 != TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpsTIFF))
4582 return 7;
4583
4584 // This one is not required. If it's missing, it's 1 (unsigned integer).
4585 if( 1 != TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &fmtTIFF))
4586 fmtTIFF = 1;
4587
4588 if (pmTIFF == PHOTOMETRIC_PALETTE)
4589 return 24;
4590
4591 //uint64_t cmTIFF = (1ULL << bpsTIFF) - 1ULL;
4592
4593 // // Dump out image metadata
4594 // std::cerr << "TIFF: " << fileName << std::endl;
4595 // std::cerr << " T WIDTH: " << wTIFF << std::endl;
4596 // std::cerr << " T HEIGHT: " << hTIFF << std::endl;
4597 // std::cerr << " T SPP: " << sppTIFF << std::endl;
4598 // std::cerr << " T PLNC: " << pcTIFF << std::endl;
4599 // std::cerr << " T PHOM: " << pmTIFF << std::endl;
4600 // std::cerr << " T BPS: " << bpsTIFF << std::endl;
4601 // std::cerr << " T MAX: " << cmTIFF << std::endl;
4602 // std::cerr << " T FMT: " << fmtTIFF << std::endl;
4603
4604 // Check file image size and reallocate aRamCanvas
4605 if(wTIFF < 1)
4606 return 8;
4607
4608 if(hTIFF < 1)
4609 return 9;
4610
4611 resizeCanvas(wTIFF, hTIFF);
4612
4613 uint32_t wRC = getNumPixX();
4614
4615 if ((pcTIFF != PLANARCONFIG_CONTIG) && (pcTIFF != PLANARCONFIG_SEPARATE))
4616 return 22;
4617
4618 if(wTIFF != wRC)
4619 return 12;
4620
4621 uint32_t hRC = getNumPixY();
4622
4623 if(hTIFF != hRC)
4624 return 14;
4625
4626 uint16_t sppRC = colorT::channelCount;
4627
4628 // MJR TODO NOTE readTIFFfile: We could read what we can instead of exiting. Check code is in the loop already to do that..
4629 if(sppTIFF != sppRC)
4630 return 19;
4631
4632 uint16_t bpsRC = colorT::bitsPerPixel / sppRC;
4633
4634 if(bpsTIFF != bpsRC)
4635 return 20;
4636
4637 // We only suport SAMPLEFORMAT_UINT & SAMPLEFORMAT_IEEEFP
4638 if ((fmtTIFF != SAMPLEFORMAT_UINT) && (fmtTIFF != SAMPLEFORMAT_IEEEFP))
4639 return 18;
4640
4641 if (( colorType::chanIsInt && (SAMPLEFORMAT_UINT != 1)) ||
4642 (!(colorType::chanIsInt) && (SAMPLEFORMAT_IEEEFP != 3)))
4643 return 21;
4644
4645 bool yNat = !(isIntAxOrientationNaturalY());
4646 bool xNat = isIntAxOrientationNaturalX();
4647 tsize_t scanlinesize = TIFFScanlineSize(tif);
4648 tdata_t scanLineBuffer = _TIFFmalloc(scanlinesize);
4649
4650 if(scanLineBuffer == NULL)
4651 return 16;
4652
4653 if (pcTIFF == PLANARCONFIG_CONTIG) { // Chunky
4654 for(uint32_t row=0; row<hTIFF; row++) {
4655 if( !(TIFFReadScanline(tif, scanLineBuffer, row)))
4656 return 17;
4657 char* p = (char*)(scanLineBuffer);
4658 for(uint32_t col=0; col<wTIFF; col++) {
4659 int x = (xNat ? col : wTIFF-col-1);
4660 int y = (yNat ? row : hTIFF-row-1);
4661 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4662 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4663 p = p + (bpsTIFF/8);
4664 }
4665 }
4666 }
4667 } else if (pcTIFF == PLANARCONFIG_SEPARATE) { // planar
4668 for(uint16_t samp=0; samp<sppTIFF; samp++) {
4669 for(uint32_t row=0; row<hTIFF; row++) {
4670 if( !(TIFFReadScanline(tif, scanLineBuffer, row, samp)))
4671 return 17;
4672 char* p = (char*)(scanLineBuffer);
4673 for(uint32_t col=0; col<wTIFF; col++) {
4674 int x = (xNat ? col : wTIFF-col-1);
4675 int y = (yNat ? row : hTIFF-row-1);
4676 getPxColorRefNC(x, y).setChan(samp, static_cast<colorChanType>(*p));
4677 p = p + (bpsTIFF/8);
4678 }
4679 }
4680 }
4681 }
4682
4683 _TIFFfree(scanLineBuffer);
4684 TIFFClose(tif);
4685 return 0;
4686#endif
4687 }
4688
4689////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4690 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4691 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4692 inline bool
4694#ifndef MRASTER_FOUND_TIFF
4695 return true;
4696#else
4697 return false;
4698#endif
4699 }
4700
4701////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4702 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4703 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4706 double Xo,
4707 double Yo,
4708 double oScale,
4709 colorArgType errorColor,
4710 interpolationType interpMethod) {
4711 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4712 for(intCrdT y=0; y<numPixY; y++) {
4713 for(intCrdT x=0; x<numPixX; x++) {
4714 double xT = (x-Xo);
4715 double yT = (y-Yo);
4716 mjr::point2d<double> fv = f(xT, yT);
4717 double xS = fv.x / oScale + Xo;
4718 double yS = fv.y / oScale + Yo;
4719 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4720 newRamCanvas.drawPointNC(x, y, errorColor);
4721 } else {
4722 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4723 }
4724 }
4725 }
4726 return newRamCanvas;
4727 }
4728
4729////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4730 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4731 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4734 double Xo,
4735 double Yo,
4736 double oScale,
4737 colorArgType errorColor,
4738 interpolationType interpMethod) {
4739 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4740 for(intCrdT y=0; y<numPixY; y++) {
4741 for(intCrdT x=0; x<numPixX; x++) {
4742 double xT = x-Xo;
4743 double yT = y-Yo;
4744 double xS = (HAMatrix[0] * xT + HAMatrix[1] * yT + HAMatrix[2]) / oScale + Xo;
4745 double yS = (HAMatrix[3] * xT + HAMatrix[4] * yT + HAMatrix[5]) / oScale + Yo;
4746 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4747 newRamCanvas.drawPointNC(x, y, errorColor);
4748 } else {
4749 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4750 }
4751 }
4752 }
4753 return newRamCanvas;
4754 }
4755
4756////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4757 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4758 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4761 double rScale,
4762 double Xo,
4763 double Yo,
4764 double oScale,
4765 colorArgType errorColor,
4766 interpolationType interpMethod) {
4767 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4768 for(intCrdT y=0; y<numPixY; y++) {
4769 for(intCrdT x=0; x<numPixX; x++) {
4770 double xT = (x - Xo);
4771 double yT = (y - Yo);
4772 double rT = std::hypot(xT, yT) / rScale;
4773 // double rS = mjr::math::uply::eval(RPoly, rT);
4774 double rS = RPoly[0];
4775 for (unsigned int i=1; i<RPoly.size(); i++)
4776 rS = rS*rT + RPoly[i];
4777 double xS = xT * rS / oScale + Xo;
4778 double yS = yT * rS / oScale + Yo;
4779 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4780 newRamCanvas.drawPointNC(x, y, errorColor);
4781 } else {
4782 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4783 }
4784 }
4785 }
4786 return newRamCanvas;
4787 }
4788
4789////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4790 template <class colorT, class intCrdT, class fltCrdT, bool enableDrawModes>
4791 requires (std::is_integral<intCrdT>::value && std::is_signed<intCrdT>::value && std::is_floating_point<fltCrdT>::value)
4794 std::vector<double> const& BiPolyY,
4795 double Xo,
4796 double Yo,
4797 double oScale,
4798 colorArgType errorColor,
4799 interpolationType interpMethod) {
4800 ramCanvasTpl<colorT, intCrdT, fltCrdT, enableDrawModes> newRamCanvas(numPixX, numPixY);
4801 for(intCrdT y=0; y<numPixY; y++) {
4802 for(intCrdT x=0; x<numPixX; x++) {
4803 double xT = (x-Xo);
4804 double yT = (y-Yo);
4805 double xS = mjr::math::bply::eval(BiPolyX, xT, yT) / oScale + Xo;
4806 double yS = mjr::math::bply::eval(BiPolyY, xT, yT) / oScale + Yo;
4807 if (isCliped(static_cast<intCrdT>(xS), static_cast<intCrdT>(yS))) {
4808 newRamCanvas.drawPointNC(x, y, errorColor);
4809 } else {
4810 newRamCanvas.drawPointNC(x, y, getPxColorInterpolate(xS, yS, interpMethod));
4811 }
4812 }
4813 }
4814 return newRamCanvas;
4815 }
4816
4817} // end namespace mjr
4818
4819#define MJR_INCLUDE_ramCanvasTpl
4820#endif
User include file for color types.
Internal include file for ramCanvas types.
Template Class used to house colors for ramCanvas objects.
static constexpr herChar chars[3935]
Data for each hershey font
font
Enum for hershey font names.
static constexpr int ascii2hershey[5][95]
ASCII to Hershey Character Number mapping array.
Handy class to hold a point in 2D (integer or real)
Definition MRpoint2d.hpp:46
coordT x
X coordinate.
Definition MRpoint2d.hpp:48
coordT y
Y coordinate.
Definition MRpoint2d.hpp:49
Colorize a ramCanvasTpl with integer channels using a color scheme.
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
This class is an incomplete rcConverter (no getPxColorNC method) that provides a nice base for homoge...
inRamCanvasT::coordIntType getNumPixX()
inRamCanvasT::coordIntType getNumPixY()
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
Convert a ramCanvasTpl to a greyscale image using colorT::intensity().
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBAbyte colorType
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBAdbl colorType
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBbyte colorType
colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y)
inRamCanvasT::colorType::colConRGBdbl colorType
Class providing off-screen drawing functionality.
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)
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
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)
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.
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)