mirror of
				https://bitbucket.org/mfeemster/fractorium.git
				synced 2025-10-31 01:10:24 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			253 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #pragma once
 | |
| 
 | |
| #include "Point.h"
 | |
| 
 | |
| /// <summary>
 | |
| /// CarToRas class.
 | |
| /// </summary>
 | |
| 
 | |
| namespace EmberNs
 | |
| {
 | |
| /// <summary>
 | |
| /// When iterating, everything is positioned in terms of a carteseian plane with 0,0 in the center like so:
 | |
| /// [-1,1]			[1,1]
 | |
| /// [-1,-1]			[1,-1]
 | |
| /// However, when accumulating to the histogram, the data is stored in the traditional raster coordinate system
 | |
| /// of 0,0 at the top left and x,y at the bottom right. This class provides functionality to convert from one
 | |
| /// to the other and is used when accumulating a sub batch of iteration results to the histogram.
 | |
| /// Note the functions use reference arguments for the converted values because they are slightly faster than returning a value.
 | |
| /// Template argument expected to be float or double.
 | |
| /// </summary>
 | |
| template <typename T>
 | |
| class EMBER_API CarToRas
 | |
| {
 | |
| public:
 | |
| 	/// <summary>
 | |
| 	/// Empty constructor. This class should never be used unless it's been properly constructed with the constructor that takes arguments.
 | |
| 	/// </summary>
 | |
| 	CarToRas()
 | |
| 	{
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Constructor that takes arguments to set up the bounds and passes them to Init().
 | |
| 	/// </summary>
 | |
| 	/// <param name="carLlX">The lower left x of the cartesian plane</param>
 | |
| 	/// <param name="carLlY">The lower left y of the cartesian plane</param>
 | |
| 	/// <param name="carUrX">The upper right x of the cartesian plane</param>
 | |
| 	/// <param name="carUrY">The upper right y of the cartesian plane</param>
 | |
| 	/// <param name="rasW">The width in pixels of the raster image/histogram</param>
 | |
| 	/// <param name="rasH">The height in pixels of the raster image/histogram</param>
 | |
| 	/// <param name="aspectRatio">The aspect ratio, generally 1</param>
 | |
| 	CarToRas(T carLlX, T carLlY, T carUrX, T carUrY, unsigned int rasW, unsigned int rasH, T aspectRatio)
 | |
| 	{
 | |
| 		Init(carLlX, carLlY, carUrX, carUrY, rasW, rasH, aspectRatio);
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Default copy constructor.
 | |
| 	/// </summary>
 | |
| 	/// <param name="carToRas">The CarToRas object to copy</param>
 | |
| 	CarToRas(const CarToRas<T>& carToRas)
 | |
| 	{
 | |
| 		CarToRas<T>::operator=<T>(carToRas);
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Copy constructor to copy a CarToRas object of type U.
 | |
| 	/// </summary>
 | |
| 	/// <param name="carToRas">The CarToRas object to copy</param>
 | |
| 	template <typename U>
 | |
| 	CarToRas(const CarToRas<U>& carToRas)
 | |
| 	{
 | |
| 		CarToRas<T>::operator=<U>(carToRas);
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Default assignment operator.
 | |
| 	/// </summary>
 | |
| 	/// <param name="carToRas">The CarToRas object to copy</param>
 | |
| 	CarToRas<T>& operator = (const CarToRas<T>& carToRas)
 | |
| 	{
 | |
| 		if (this != &carToRas)
 | |
| 			CarToRas<T>::operator=<T>(carToRas);
 | |
| 
 | |
| 		return *this;
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Assignment operator to assign a CarToRas object of type U.
 | |
| 	/// </summary>
 | |
| 	/// <param name="carToRas">The CarToRas object to copy.</param>
 | |
| 	/// <returns>Reference to updated self</returns>
 | |
| 	template <typename U>
 | |
| 	CarToRas<T>& operator = (const CarToRas<U>& carToRas)
 | |
| 	{
 | |
| 		m_RasWidth = carToRas.RasWidth();
 | |
| 		m_RasHeight = carToRas.RasHeight();
 | |
| 		m_OneRow = T(carToRas.OneRow());
 | |
| 		m_OneCol = T(carToRas.OneCol());
 | |
| 		m_PixPerImageUnitW = T(carToRas.PixPerImageUnitW());
 | |
| 		m_RasLlX = T(carToRas.RasLlX());
 | |
| 		m_PixPerImageUnitH = T(carToRas.PixPerImageUnitH());
 | |
| 		m_RasLlY = T(carToRas.RasLlY());
 | |
| 		m_CarLlX = T(carToRas.CarLlX());
 | |
| 		m_CarLlY = T(carToRas.CarLlY());
 | |
| 		m_CarUrX = T(carToRas.CarUrX());
 | |
| 		m_CarUrY = T(carToRas.CarUrY());
 | |
| 		m_PadCarLlX = T(carToRas.PadCarLlX());
 | |
| 		m_PadCarLlY = T(carToRas.PadCarLlY());
 | |
| 		m_PadCarUrX = T(carToRas.PadCarUrX());
 | |
| 		m_PadCarUrY = T(carToRas.PadCarUrY());
 | |
| 
 | |
| 		return *this;
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Initialize the dimensions with the specified bounds.
 | |
| 	/// </summary>
 | |
| 	/// <param name="carLlX">The lower left x of the cartesian plane</param>
 | |
| 	/// <param name="carLlY">The lower left y of the cartesian plane</param>
 | |
| 	/// <param name="carUrX">The upper right x of the cartesian plane</param>
 | |
| 	/// <param name="carUrY">The upper right y of the cartesian plane</param>
 | |
| 	/// <param name="rasW">The width in pixels of the raster image/histogram</param>
 | |
| 	/// <param name="rasH">The height in pixels of the raster image/histogram</param>
 | |
| 	/// <param name="aspectRatio">The aspect ratio, generally 1</param>
 | |
| 	void Init(T carLlX, T carLlY, T carUrX, T carUrY, unsigned int rasW, unsigned int rasH, T aspectRatio)
 | |
| 	{
 | |
| 		m_RasWidth = rasW;
 | |
| 		m_RasHeight = rasH;
 | |
| 
 | |
| 		m_CarLlX = carLlX;
 | |
| 		m_CarLlY = carLlY;
 | |
| 		m_CarUrX = carUrX;
 | |
| 		m_CarUrY = carUrY;
 | |
| 
 | |
| 		T carW = m_CarUrX - m_CarLlX;//Right minus left.
 | |
| 		T carH = m_CarUrY - m_CarLlY;//Top minus bottom.
 | |
| 		T invSizeW = T(1.0) / carW;
 | |
| 		T invSizeH = T(1.0) / carH;
 | |
| 
 | |
| 		m_PixPerImageUnitW = (T)rasW * invSizeW;
 | |
| 		m_RasLlX = m_PixPerImageUnitW * carLlX;
 | |
| 
 | |
| 		m_PixPerImageUnitH = (T)rasH * invSizeH;
 | |
| 		m_RasLlY = m_PixPerImageUnitH * carLlY;
 | |
| 
 | |
| 		m_OneRow = abs(m_CarUrY - m_CarLlY) / m_RasHeight;
 | |
| 		m_OneCol = abs(m_CarUrX - m_CarLlX) / m_RasWidth;
 | |
| 
 | |
| 		m_PadCarLlX = m_CarLlX + m_OneCol;
 | |
| 		m_PadCarUrX = m_CarUrX - m_OneCol;
 | |
| 
 | |
| 		m_PadCarLlY = m_CarLlY + m_OneRow;
 | |
| 		m_PadCarUrY = m_CarUrY - m_OneRow;
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Convert a cartesian x, y coordinate to a raster x, y coordinate.
 | |
| 	/// This will flip the Y coordinate, so points that hit the bottom of the cartesian plane will
 | |
| 	/// be mapped to the top of the histogram and vice versa.
 | |
| 	/// There is a very slim chance that a point will be right on the border and will technically be in bounds, passing the InBounds() test,
 | |
| 	/// but ends up being mapped to a histogram bucket that is out of bounds due to roundoff error. Perform an additional check after this call to make sure the
 | |
| 	/// mapped point is in bounds.
 | |
| 	/// </summary>
 | |
| 	/// <param name="cartX">The cartesian x</param>
 | |
| 	/// <param name="cartY">The cartesian y</param>
 | |
| 	/// <param name="rasX">The converted raster x</param>
 | |
| 	/// <param name="rasY">The converted raster y</param>
 | |
| 	inline void Convert(T cartX, T cartY, unsigned int& rasX, unsigned int& rasY)
 | |
| 	{
 | |
| 		rasX = (unsigned int)(m_PixPerImageUnitW * cartX - m_RasLlX);
 | |
| 		rasY = (unsigned int)(m_RasLlY - (m_PixPerImageUnitH * cartY));
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Convert a cartesian x, y coordinate to a single raster buffer index.
 | |
| 	/// This will flip the Y coordinate, so points that hit the bottom of the cartesian plane will
 | |
| 	/// be mapped to the top of the histogram and vice versa.
 | |
| 	/// There is a very slim chance that a point will be right on the border and will technically be in bounds, passing the InBounds() test,
 | |
| 	/// but ends up being mapped to a histogram bucket that is out of bounds due to roundoff error. Perform an additional check after this call to make sure the
 | |
| 	/// mapped point is in bounds.
 | |
| 	/// </summary>
 | |
| 	/// <param name="cartX">The cartesian x</param>
 | |
| 	/// <param name="cartY">The cartesian y</param>
 | |
| 	/// <param name="singleBufferIndex">The converted single raster buffer index</param>
 | |
| 	inline void Convert(T cartX, T cartY, unsigned int& singleBufferIndex)
 | |
| 	{
 | |
| 		singleBufferIndex = (unsigned int)(m_PixPerImageUnitW * cartX - m_RasLlX) + (m_RasWidth * (unsigned int)(m_PixPerImageUnitH * cartY - m_RasLlY));
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Convert a cartesian x, y point to a single raster buffer index.
 | |
| 	/// This will flip the Y coordinate, so points that hit the bottom of the cartesian plane will
 | |
| 	/// be mapped to the top of the histogram and vice versa.
 | |
| 	/// This is the most efficient possible way of converting, consisting of only
 | |
| 	/// a multiply and subtract per coordinate element.
 | |
| 	/// There is a very slim chance that a point will be right on the border and will technically be in bounds, passing the InBounds() test,
 | |
| 	/// but ends up being mapped to a histogram bucket that is out of bounds due to roundoff error. Perform an additional check after this call to make sure the
 | |
| 	/// mapped point is in bounds.
 | |
| 	/// </summary>
 | |
| 	/// <param name="point">The cartesian y</param>
 | |
| 	/// <param name="singleBufferIndex">The converted single raster buffer index</param>
 | |
| 	inline void Convert(Point<T>& point, unsigned int& singleBufferIndex)
 | |
| 	{
 | |
| 		singleBufferIndex = (unsigned int)(m_PixPerImageUnitW * point.m_X - m_RasLlX) + (m_RasWidth * (unsigned int)(m_PixPerImageUnitH * point.m_Y - m_RasLlY));
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Determine if a point in the cartesian plane can be converted to a point within the raster plane.
 | |
| 	/// There is a very slim chance that a point will be right on the border and will technically be in bounds, passing the InBounds() test,
 | |
| 	/// but ends up being mapped to a histogram bucket that is out of bounds due to roundoff error. Perform an additional check after this call to make sure the
 | |
| 	/// mapped point is in bounds.
 | |
| 	/// </summary>
 | |
| 	/// <param name="point">The point to test</param>
 | |
| 	/// <returns>True if within bounds, else false</returns>
 | |
| 	inline bool InBounds(Point<T>& point)
 | |
| 	{
 | |
| 		//Debug check for hitting the very first pixel in the image.
 | |
| 		//if (point.m_Y > m_CarLlY && point.m_Y <= m_PadCarLlY && //Mapped to top row...
 | |
| 		//	point.m_X > m_CarLlX && point.m_X <= m_PadCarLlX)//...first col.
 | |
| 		//{
 | |
| 		//	cout << "First pixel hit." << endl;
 | |
| 		//}
 | |
| 
 | |
| 		return point.m_X >= m_CarLlX &&
 | |
| 			   point.m_X < m_CarUrX &&
 | |
| 			   point.m_Y < m_CarUrY &&
 | |
| 			   point.m_Y >= m_CarLlY;
 | |
| 	}
 | |
| 
 | |
| 	/// <summary>
 | |
| 	/// Accessors.
 | |
| 	/// </summary>
 | |
| 	inline unsigned int RasWidth() const { return m_RasWidth; }
 | |
| 	inline unsigned int RasHeight() const { return m_RasHeight; }
 | |
| 	inline T OneRow() const { return m_OneRow; }
 | |
| 	inline T OneCol() const { return m_OneCol; }
 | |
| 	inline T PixPerImageUnitW() const { return m_PixPerImageUnitW; }
 | |
| 	inline T RasLlX() const { return m_RasLlX; }
 | |
| 	inline T PixPerImageUnitH() const { return m_PixPerImageUnitH; }
 | |
| 	inline T RasLlY() const { return m_RasLlY; }
 | |
| 	inline T CarLlX() const { return m_CarLlX; }
 | |
| 	inline T CarLlY() const { return m_CarLlY; }
 | |
| 	inline T CarUrX() const { return m_CarUrX; }
 | |
| 	inline T CarUrY() const { return m_CarUrY; }
 | |
| 	inline T PadCarLlX() const { return m_PadCarLlX; }
 | |
| 	inline T PadCarLlY() const { return m_PadCarLlY; }
 | |
| 	inline T PadCarUrX() const { return m_PadCarUrX; }
 | |
| 	inline T PadCarUrY() const { return m_PadCarUrY; }
 | |
| 
 | |
| private:
 | |
| 	unsigned int m_RasWidth, m_RasHeight;//The width and height of the raster image.
 | |
| 	T m_OneRow;//The distance that one raster row represents in the cartesian plane.
 | |
| 	T m_OneCol;//The distance that one raster column represents in the cartesian plane.
 | |
| 	T m_PixPerImageUnitW;//The number of columns in the raster plane that a horizontal distance of 1 in the cartesian plane represents. The higher the number, the more zoomed in.
 | |
| 	T m_RasLlX;//The lower left x of the raster image plane.
 | |
| 	T m_PixPerImageUnitH;//The number of rows in the raster plane that a vertical distance of 1 in the cartesian plane represents. The higher the number, the more zoomed in.
 | |
| 	T m_RasLlY;//The lower left y of the raster image plane.
 | |
| 	T m_CarLlX, m_CarLlY, m_CarUrX, m_CarUrY;//The bounds of the cartesian plane.
 | |
| 	T m_PadCarLlX, m_PadCarLlY, m_PadCarUrX, m_PadCarUrY;//The bounds of the cartesian plane padded by one raster row and column on each side.
 | |
| };
 | |
| }
 | 
