CanadianMachines / MachineLib / CardReader.cpp
CardReader.cpp
Raw
/**
 * @file CardReader.cpp
 * @author sriram
 */

#include "pch.h"
#include "CardReader.h"
#include "AirSource.h"
#include "BezierEnd.h"


/// Image for the back of the card reader
const std::wstring CardReaderBackImage = L"/images/card-reader-back.png";

/// Image for the front of the card reader
const std::wstring CardReaderFrontImage = L"/images/card-reader-front.png";


// The card actual dimensions are 847 by 379 pixels,
// a size chosen to make the column spacing exactly
// 10 pixels. We draw it much smaller than that on the screen

/// Width to draw the card on the screen in pixels
const int CardWidth = 132;

/// Height to draw the card on the screen in pixels
const int CardLength = 297;

/// Amount of offset the center of the card so it will
/// appear at the right place relative to the card reader.
const int CardOffsetX = 126;

/// Y dimension of the offset
const int CardOffsetY = 65;

// These values are all for the underlying image. They
// can be used for find the punches.

/// Width of a card column in pixels
const int CardColumnWidth = 10;

/// Height of a card row in pixels
const int CardRowHeight = 29;

/// X offset for the first column (left side)
const int CardColumn0X = 24;

/// Y offset to the first row (0's)
/// There are actually two rows above this that can be used
const int CardRow0Y = 78;

/// Width of a punched hole
const int CardPunchWidth = 8;

/// Height of a punched hole
const int CardPunchHit = 20;

/// Any average luminance below this level is considered a punched hole
const double CardPunchLuminance = 0.1;

/// number of columns in card
const int NumColumns = 80;

//
// These values are for the outputs of the card reader,
// where the tubing attaches.
//

/// Y offset to the first card reader output in pixels
const int OutputOffsetY = -92;

/// X offset to the first card reader output in pixels
const int OutputOffsetX = -35;

/// X spacing for the outputs
const double OutputSpacingX = 10.7;

///number of sources
const int NumSources = 10;

/**
 * constructor
 * @param resourcesDir
 */
CardReader::CardReader(std::wstring resourcesDir)
{
	for(int i=0; i<NumSources; i++)
	{
		auto source = std::make_shared<AirSource>();
		mSources.push_back(source);
	}

	mBack.SetImage(resourcesDir + CardReaderBackImage);
	mBack.Rectangle(-mBack.GetImageWidth() / 2, 0);

	mFront.SetImage(resourcesDir + CardReaderFrontImage);
	mFront.Rectangle(-mFront.GetImageWidth() / 2, 0);

	mCard.Rectangle(CardOffsetX, CardOffsetY, CardLength, CardWidth);
	mCard.SetRotation(-0.25);
}

/**
 * draw function
 * @param graphics
 * @param x
 * @param y
 */
void CardReader::Draw(std::shared_ptr<wxGraphicsContext> graphics, double x, double y)
{
	mBack.DrawPolygon(graphics, x+GetComponentLocation().x, y+GetComponentLocation().y);

	auto cardScale = (double)CardLength / mCard.GetImageWidth();
	mCard.DrawPolygon(graphics, x+GetComponentLocation().x, y + (mColumn-1) * cardScale * CardColumnWidth+ GetComponentLocation().y);

	mFront.DrawPolygon(graphics, x+GetComponentLocation().x, y+GetComponentLocation().y);
}


/**
 * Determine if a hole is punched in the card.
 * @param column Column on the card, from 0 (left of first column) to 80 (last column)
 * @param row Row on the card, -2 to 9.
 * @return True if hole is punched at column, row
*/
bool CardReader::IsPunched(int column, int row)
{
	auto luminance = mCard.AverageLuminance(CardColumn0X + (column - 1) * CardColumnWidth,
											CardRow0Y + CardRowHeight * row, CardPunchWidth, CardPunchHit);
	return luminance < CardPunchLuminance;
}

/**
 * virtual setter for time
 * @param time
 */
void CardReader::SetTime(double time)
{
	double beat = time * mBeatsPerMinute / 60.0;
	double remainder = fmod(beat, 1);
	mColumn = (int)beat;

	if(mColumn < NumColumns)
	{
		auto pressure = remainder > 0.5 ? 0.0 : 1.0;
		SendPressure(pressure);
	}
	else
	{
		mColumn=79;
	}
}

/**
 * setter for card
 * @param imagePath
 */
void CardReader::SetCard(std::wstring imagePath)
{
	mCard.SetImage(imagePath);
}


/**
 * send pressure across components
 * @param pressure
 */
void CardReader::SendPressure(double pressure)
{

	// Determine what is punched in this row
	for(int row = 0; row < NumSources; row++)
	{
		bool punched = IsPunched(mColumn, row);
		if(punched)
		{
			mSources[row]->SendPressure(pressure);
		}
	}
}

/**
 * sets location for reader and sources
 * @param x
 * @param y
 */
void CardReader::SetPosition(double x, double y)
{
	Component::SetPosition(x, y);

	for (int row = 0; row < NumSources; row++)
	{
		mSources[row]->SetPosition(
			(int)(x + OutputOffsetX + OutputSpacingX * row),
			y + OutputOffsetY);
	}
}