The Colour Chart Generator in C++


Introduction

This is a C++ coding test. It is expected that this task should take a few hours to complete.

Task description

Overview

When designing graphics hardware it is useful to be able to display various test patterns and colour ramps. The task is to write a command-line application to generate some of these test patterns. In the simplest case this program will produce a colour ramp starting with one colour on one side of the display and changing smoothly to a second colour on the other side. In the most complex case there will be a different colour in each corner of the display and each pixel on the display will show the appropriate mix of these four colours.

Input

The program should be invoked by the following command line:

./ramp.exe display tl tr [bl] [br]

where

  • display is the name of the display device
  • tl is the top left colour value
  • tr is the top right colour value
  • bl is the bottom left colour value [optional, defaults to tl]
  • br is the bottom right colour value [optional, defaults to tr]

The colour values are specified as 16-bit RGB565 pixels in hex or decimal. The bits for each colour are assigned as follows:

Bit	15	14	13	12	11	10	9	8	7	6	5	4	3	2	1	0
Colour	R4	R3	R2	R1	R0	G5	G4	G3	G2	G1	G0	B4	B3	B2	B1	B0

For example,

  • White is 0xffff
  • Black is 0x0000
  • Pure blue is 0x001f
  • Pure green is 0x07e0
  • Pure red is 0xf800

The following inputs to the program are all valid:

  • ramp.exe display 0x0 0x2
  • ramp.exe display 65 255
  • ramp.exe display 200 0 30
  • ramp.exe display 0 0 3200 1800
  • etc

Output

The program must fill the display with a colour ramp as defined by the input values. Each corner of the display must have the specified colour and the pixels in the middle must be a linear mix of those colours.

The image is output on the display using the Display class which is provided. The size method returns the size of the display and the draw method is used to draw a row of 16-bit RGB565 pixels on the display. Finally, the present method is called to display the pixels.

Assessment

The results of this task will be assessed in the following areas:

  • Correct program operation for all input values
  • Clarity of design
  • Consistent coding style and demonstrated use of C++ features
  • Testing strategy (Supplied unit tests, etc)
  • Appropriate error handling

You must provide full source code and a brief description. The program will be tested with a variety of input values. The implementation of the Display class is provided below.

Notes

Correct behaviour is much more important than good performance.

This task is harder than it appears: there are a number of pitfalls and difficult cases to allow for. In particular, make sure that the colours are spread evenly when there are only a few different colours across the display. For example, a ramp from 0 to 0xf, over a width of 16 pixels, should attain each value exactly once.

Display Class implementation

Display.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef DISPLAY_H_INCLUDED
#define DISPLAY_H_INCLUDED
 
#include <vector>
#include <string>
#include <cstdint>
 
struct Point
{
  int16_t x;
  int16_t y;
};
 
struct Dimension
{
  uint16_t width;
  uint16_t height;
};
 
class Display
{
public:
  Display(const std::string& name);
  ~Display() = default;
 
  Dimension size() const;
  void draw(Point point, const uint16_t* pixels, uint16_t width);
  void present();
 
private:
  const std::string m_name;
  std::vector<uint16_t> m_frameBuffer;
};
 
#endif
#ifndef DISPLAY_H_INCLUDED
#define DISPLAY_H_INCLUDED

#include <vector>
#include <string>
#include <cstdint>

struct Point
{
  int16_t x;
  int16_t y;
};

struct Dimension
{
  uint16_t width;
  uint16_t height;
};

class Display
{
public:
  Display(const std::string& name);
  ~Display() = default;

  Dimension size() const;
  void draw(Point point, const uint16_t* pixels, uint16_t width);
  void present();

private:
  const std::string m_name;
  std::vector<uint16_t> m_frameBuffer;
};

#endif

Display.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "Display.h"
 
#include <cstdio>
#include <cstring>
 
namespace {
  constexpr uint16_t Width = 16;
  constexpr uint16_t Height = 9;
}
 
Display::Display(const std::string& name)
  : m_name(name)
  , m_frameBuffer(Width * Height)
{
}
 
Dimension Display::size() const
{
  return { Width, Height };
}
 
void Display::draw(const Point point,
 const uint16_t *pixels,
 const uint16_t width)
{
  std::memcpy(&m_frameBuffer[point.y * Width + point.x],
  pixels,
  width * sizeof(uint16_t));
}
 
void Display::present()
{
  auto pixels = m_frameBuffer.data();
  for (int y = 0; y < Height; ++y) {
    for (int x = 0; x < Width; ++x) {
      printf("%04X ", *pixels++);
    }
    printf("\n");
  }
}
#include "Display.h"

#include <cstdio>
#include <cstring>

namespace {
  constexpr uint16_t Width = 16;
  constexpr uint16_t Height = 9;
}

Display::Display(const std::string& name)
  : m_name(name)
  , m_frameBuffer(Width * Height)
{
}

Dimension Display::size() const
{
  return { Width, Height };
}

void Display::draw(const Point point,
 const uint16_t *pixels,
 const uint16_t width)
{
  std::memcpy(&m_frameBuffer[point.y * Width + point.x],
  pixels,
  width * sizeof(uint16_t));
}

void Display::present()
{
  auto pixels = m_frameBuffer.data();
  for (int y = 0; y < Height; ++y) {
    for (int x = 0; x < Width; ++x) {
      printf("%04X ", *pixels++);
    }
    printf("\n");
  }
}

Colour Chart Ramp ScreenShot

displaylink The Colour Chart Generator in C++ c / c++ coding exercise interview questions

displaylink coding exercise

The Colour Chart Generator

The main.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// command line utility: ./ramp 
// Compile: make ramp
 
#include <iostream>
#include <string>
#include <cstdint>
#include <memory>
#include "utils.h"
#include "ramp.h"
 
using namespace std;
 
void help() 
{
  cout << "The following inputs to the program are all valid:" << endl;
  cout << "  ./ramp display 0x0 0x2" << endl;
  cout << "  ./ramp display 65 255" << endl;
  cout << "  ./ramp display 200 0 30" << endl;
  cout << "  ./ramp display 0 0 3200 1800" << endl;
}
 
int main(int argc, char *argv[]) 
{
  if (argc < 4) 
  {
    help();
    return -1;
  }    
  // first three parameters are required.
  string name = argv[1];
  uint16_t tl, tr, bl, br;
  tl = convert(string(argv[2]));
  tr = convert(string(argv[3]));
  // next two are optional: bl and br
  // set default values 
  bl = tl;
  br = tr;  
  if (argc > 4) 
  {
    bl = convert(string(argv[4]));
    if (argc > 5) 
    {
      br = convert(string(argv[5])); 
    } 
  }  
  shared_ptr<Ramp> ramp(new Ramp(name, tl, tr, bl, br));
  // render it to display buffer
  ramp->render();
  // print it to console
  ramp->getDisplayObject()->present(); 
  return 0;
}
// command line utility: ./ramp 
// Compile: make ramp

#include <iostream>
#include <string>
#include <cstdint>
#include <memory>
#include "utils.h"
#include "ramp.h"

using namespace std;

void help() 
{
  cout << "The following inputs to the program are all valid:" << endl;
  cout << "  ./ramp display 0x0 0x2" << endl;
  cout << "  ./ramp display 65 255" << endl;
  cout << "  ./ramp display 200 0 30" << endl;
  cout << "  ./ramp display 0 0 3200 1800" << endl;
}

int main(int argc, char *argv[]) 
{
  if (argc < 4) 
  {
    help();
    return -1;
  }    
  // first three parameters are required.
  string name = argv[1];
  uint16_t tl, tr, bl, br;
  tl = convert(string(argv[2]));
  tr = convert(string(argv[3]));
  // next two are optional: bl and br
  // set default values 
  bl = tl;
  br = tr;  
  if (argc > 4) 
  {
    bl = convert(string(argv[4]));
    if (argc > 5) 
    {
      br = convert(string(argv[5])); 
    } 
  }  
  shared_ptr<Ramp> ramp(new Ramp(name, tl, tr, bl, br));
  // render it to display buffer
  ramp->render();
  // print it to console
  ramp->getDisplayObject()->present(); 
  return 0;
}

The ramp.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Ramp class implementation
 
#include <string> 
#include <vector>
#include "ramp.h"
#include "utils.h"
 
Ramp::Ramp(const std::string& name, color tl, color tr, color bl, color br)
  : m_tl(tl)
  , m_tr(tr)
  , m_bl(bl)
  , m_br(br)
{
  display = new Display(name);
}
 
Ramp::Ramp(const std::string& name, color tl, color tr): Ramp(name, tl, tr, tl, tr)
{
}
 
Ramp::Ramp(const std::string& name, color tl, color tr, color bl): Ramp(name, tl, tr, bl, tr)  
{  
}
 
Ramp::~Ramp() 
{
  // TODO: use shared_ptr so that we don't need to explicitly free the pointer
  delete display; 
}
 
void Ramp::render() {
  // get display size
  auto dim = display->size();
  auto w = (int16_t)(dim.width - 1);
  auto h = (int16_t)(dim.height - 1);  
  // fill the coners
  display->draw({0, 0}, &m_tl, 1);
  display->draw({w, 0}, &m_tr, 1);
  display->draw({0, h}, &m_bl, 1);
  display->draw({w, h}, &m_br, 1);
  // interpolate the rest
  // TODO: the following loop can be unrolled to improve the performance
  // another improvement is creating a local buffer and call display->draw when everything is done
  for (int16_t x = 0; x < dim.width; ++ x) 
  {
    for (int16_t y = 0; y < dim.height; ++ y) 
    {
      // exclude 4 corners, this could be unrolled
      if ( ((x != 0) && (x != w)) || ((y != 0) && (y != h)) )  
      {        
        color c = BilinearInterpolation(m_tl, m_tr, m_bl, m_br, w, h, x, y);
        display->draw({x, y}, &c, 1);
      }
    }
  }
}
// Ramp class implementation

#include <string> 
#include <vector>
#include "ramp.h"
#include "utils.h"

Ramp::Ramp(const std::string& name, color tl, color tr, color bl, color br)
  : m_tl(tl)
  , m_tr(tr)
  , m_bl(bl)
  , m_br(br)
{
  display = new Display(name);
}

Ramp::Ramp(const std::string& name, color tl, color tr): Ramp(name, tl, tr, tl, tr)
{
}

Ramp::Ramp(const std::string& name, color tl, color tr, color bl): Ramp(name, tl, tr, bl, tr)  
{  
}

Ramp::~Ramp() 
{
  // TODO: use shared_ptr so that we don't need to explicitly free the pointer
  delete display; 
}

void Ramp::render() {
  // get display size
  auto dim = display->size();
  auto w = (int16_t)(dim.width - 1);
  auto h = (int16_t)(dim.height - 1);  
  // fill the coners
  display->draw({0, 0}, &m_tl, 1);
  display->draw({w, 0}, &m_tr, 1);
  display->draw({0, h}, &m_bl, 1);
  display->draw({w, h}, &m_br, 1);
  // interpolate the rest
  // TODO: the following loop can be unrolled to improve the performance
  // another improvement is creating a local buffer and call display->draw when everything is done
  for (int16_t x = 0; x < dim.width; ++ x) 
  {
    for (int16_t y = 0; y < dim.height; ++ y) 
    {
      // exclude 4 corners, this could be unrolled
      if ( ((x != 0) && (x != w)) || ((y != 0) && (y != h)) )  
      {        
        color c = BilinearInterpolation(m_tl, m_tr, m_bl, m_br, w, h, x, y);
        display->draw({x, y}, &c, 1);
      }
    }
  }
}

The ramp.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Ramp class declaration
 
#ifndef RAMP_H_INCLUDED
#define RAMP_H_INCLUDED
 
#include <string>
#include "display.h"
#include "types.h"
 
class Ramp
{
public:
  // overloaded constructors with 2, 3 or 4 parameters
  Ramp(const std::string& name, color tl, color tr, color bl, color br);
  Ramp(const std::string& name, color tl, color tr);
  Ramp(const std::string& name, color tl, color tr, color bl);
  
  ~Ramp();
 
  // fill the ramp to the display 
  void render();
   
  inline Display* getDisplayObject() 
  {
    return display;
  }   
  
private:
  Display *display;
  color m_tl, m_tr, m_bl, m_br;  
};
 
#endif
// Ramp class declaration

#ifndef RAMP_H_INCLUDED
#define RAMP_H_INCLUDED

#include <string>
#include "display.h"
#include "types.h"

class Ramp
{
public:
  // overloaded constructors with 2, 3 or 4 parameters
  Ramp(const std::string& name, color tl, color tr, color bl, color br);
  Ramp(const std::string& name, color tl, color tr);
  Ramp(const std::string& name, color tl, color tr, color bl);
  
  ~Ramp();

  // fill the ramp to the display 
  void render();
   
  inline Display* getDisplayObject() 
  {
    return display;
  }   
  
private:
  Display *display;
  color m_tl, m_tr, m_bl, m_br;  
};

#endif

The test utilities, simpletest.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// The Simplest Unit Test Framework for C++
 
#ifndef SIMPLETEST_H_INCLUDED
#define SIMPLETEST_H_INCLUDED
 
#include <iostream>
#include <string>
using namespace std;
 
template <typename T>
inline void AssertEquals(T a, T b, string msg = "") 
{
  if (a != b) 
  {
    cout << "AssertEquals Fails: " << a << " != " << b << " " << msg << endl;
    throw;
  }
}
 
inline void AssertTrue(bool a, string msg = "") 
{
  if (!a) 
  {
    cout << "AssertTrue Fails: " << a << " " << msg << endl;
    throw;
  }
}
 
inline void AssertFalse(bool a, string msg = "") 
{
  if (a) 
  {
    cout << "AssertFalse Fails: " << a << " " << msg << endl;
    throw;
  }
}
 
#endif
// The Simplest Unit Test Framework for C++

#ifndef SIMPLETEST_H_INCLUDED
#define SIMPLETEST_H_INCLUDED

#include <iostream>
#include <string>
using namespace std;

template <typename T>
inline void AssertEquals(T a, T b, string msg = "") 
{
  if (a != b) 
  {
    cout << "AssertEquals Fails: " << a << " != " << b << " " << msg << endl;
    throw;
  }
}

inline void AssertTrue(bool a, string msg = "") 
{
  if (!a) 
  {
    cout << "AssertTrue Fails: " << a << " " << msg << endl;
    throw;
  }
}

inline void AssertFalse(bool a, string msg = "") 
{
  if (a) 
  {
    cout << "AssertFalse Fails: " << a << " " << msg << endl;
    throw;
  }
}

#endif

And some tests test.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// The test executable
// Compile and run: make test
 
#include <iostream>
#include <string>
#include <cstdint>
#include <memory>
#include "utils.h"
#include "ramp.h"
#include "simpletest.h"
 
using namespace std;
 
int main(int argc, char *argv[]) 
{
  // tests for getColorR, getColorG and getColorB
  AssertEquals<uint16_t>(getColorR(65535), (uint16_t)31);
  AssertEquals<uint16_t>(getColorG(65535), (uint16_t)63);
  AssertEquals<uint16_t>(getColorB(65535), (uint16_t)31);
  
  // tests for getColor
  AssertEquals<uint16_t>(getColor(31, 63, 31), (uint16_t)65535);      
  
  // tests for isDecimalInteger
  AssertTrue(isDecimalInteger("1234"), "testing 1234 for isDecimalInteger");
  AssertFalse(isDecimalInteger("xxx1234"), "testing xxxx1234 for isDecimalInteger");
  
  // tests for convert
  AssertEquals<int>(convert("0x0A"), 10);
  AssertEquals<int>(convert("1234"), 1234);
  
  // tests for BilinearInterpolation
  auto c = BilinearInterpolation(1, 16, 16, 1, 16, 9, 7, 4);
  AssertEquals<uint16_t>(c, 8);
  
  // tests for display checksum
  // **** this requires changes to Display class
  shared_ptr<Ramp> ramp(new Ramp("display_test", 1, 2, 55, 66));
  // render it to display buffer
  ramp->render();
  // test the checksum
  AssertEquals<uint16_t>(ramp->getDisplayObject()->checksum(), 96);
  
  // if all tests pass, you should see the following message ^_^
  cout << "All Tests OK." << endl;
}
// The test executable
// Compile and run: make test

#include <iostream>
#include <string>
#include <cstdint>
#include <memory>
#include "utils.h"
#include "ramp.h"
#include "simpletest.h"

using namespace std;

int main(int argc, char *argv[]) 
{
  // tests for getColorR, getColorG and getColorB
  AssertEquals<uint16_t>(getColorR(65535), (uint16_t)31);
  AssertEquals<uint16_t>(getColorG(65535), (uint16_t)63);
  AssertEquals<uint16_t>(getColorB(65535), (uint16_t)31);
  
  // tests for getColor
  AssertEquals<uint16_t>(getColor(31, 63, 31), (uint16_t)65535);      
  
  // tests for isDecimalInteger
  AssertTrue(isDecimalInteger("1234"), "testing 1234 for isDecimalInteger");
  AssertFalse(isDecimalInteger("xxx1234"), "testing xxxx1234 for isDecimalInteger");
  
  // tests for convert
  AssertEquals<int>(convert("0x0A"), 10);
  AssertEquals<int>(convert("1234"), 1234);
  
  // tests for BilinearInterpolation
  auto c = BilinearInterpolation(1, 16, 16, 1, 16, 9, 7, 4);
  AssertEquals<uint16_t>(c, 8);
  
  // tests for display checksum
  // **** this requires changes to Display class
  shared_ptr<Ramp> ramp(new Ramp("display_test", 1, 2, 55, 66));
  // render it to display buffer
  ramp->render();
  // test the checksum
  AssertEquals<uint16_t>(ramp->getDisplayObject()->checksum(), 96);
  
  // if all tests pass, you should see the following message ^_^
  cout << "All Tests OK." << endl;
}

the types.h:

1
2
3
4
5
6
7
8
9
#ifndef TYPES_H_INCLUDED
#define TYPES_H_INCLUDED
 
#include <cstdint>
 
// color type
typedef uint16_t color;
 
#endif
#ifndef TYPES_H_INCLUDED
#define TYPES_H_INCLUDED

#include <cstdint>

// color type
typedef uint16_t color;

#endif

the utils.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Provides a few useful functions
 
#ifndef UTILS_H_INCLUDED
#define UTILS_H_INCLUDED
 
#include <sstream>
#include <cstdlib>
#include "types.h"
 
float BilinearInterpolation(float q11, float q12, float q21, float q22, float x1, float x2, float y1, float y2, float x, float y); 
color BilinearInterpolation(color tl, color tr, color bl, color br, uint16_t w, uint16_t h, uint16_t x, uint16_t y);
 
inline uint16_t getColorR(color c) 
{
  return c >> 11;
}
 
inline uint16_t getColorG(color c) 
{
  return (c >> 5) & 63;
}
 
inline uint16_t getColorB(color c) 
{
  return c & 31;
}
 
inline color getColor(uint16_t r, uint16_t g, uint16_t b) 
{
  return ((r & 31) << 11) | ((g & 63) << 5) | (b & 31);  
}
 
// check if dec integer
inline bool isDecimalInteger(std::string s) 
{
  int len = s.size();
  if (0 == len) 
  {
    return false;
  }
  for (int i = 0; i < len; ++ i) 
  {
    if ( !(s[i] >= '0' && s[i] <= '9')) 
    {
      return false;
    }
  }
  return true;
}
 
// convert string to dec or hex number 
inline int convert(std::string str) 
{
  if (isDecimalInteger(str)) {
    return std::stoi(str, nullptr, 10);  
  }
  return std::stoi(str, nullptr, 16);
}
 
#endif
// Provides a few useful functions

#ifndef UTILS_H_INCLUDED
#define UTILS_H_INCLUDED

#include <sstream>
#include <cstdlib>
#include "types.h"

float BilinearInterpolation(float q11, float q12, float q21, float q22, float x1, float x2, float y1, float y2, float x, float y); 
color BilinearInterpolation(color tl, color tr, color bl, color br, uint16_t w, uint16_t h, uint16_t x, uint16_t y);

inline uint16_t getColorR(color c) 
{
  return c >> 11;
}

inline uint16_t getColorG(color c) 
{
  return (c >> 5) & 63;
}

inline uint16_t getColorB(color c) 
{
  return c & 31;
}

inline color getColor(uint16_t r, uint16_t g, uint16_t b) 
{
  return ((r & 31) << 11) | ((g & 63) << 5) | (b & 31);  
}

// check if dec integer
inline bool isDecimalInteger(std::string s) 
{
  int len = s.size();
  if (0 == len) 
  {
    return false;
  }
  for (int i = 0; i < len; ++ i) 
  {
    if ( !(s[i] >= '0' && s[i] <= '9')) 
    {
      return false;
    }
  }
  return true;
}

// convert string to dec or hex number 
inline int convert(std::string str) 
{
  if (isDecimalInteger(str)) {
    return std::stoi(str, nullptr, 10);  
  }
  return std::stoi(str, nullptr, 16);
}

#endif

The BilinearInterpolation has been detailed here – however it might be refactored into a class so it doesn’t take so many parameters.

And finally the utils.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Utility implementation
#include "utils.h"
 
// based on: https://en.wikipedia.org/wiki/Bilinear_interpolation
float BilinearInterpolation(float q11, float q12, float q21, float q22, float x1, float x2, float y1, float y2, float x, float y) 
{
  float x2x1, y2y1, x2x, y2y, yy1, xx1;
  x2x1 = x2 - x1;
  y2y1 = y2 - y1;
  x2x = x2 - x;
  y2y = y2 - y;
  yy1 = y - y1;
  xx1 = x - x1;
  return 1.0 / (x2x1 * y2y1) * (
    q11 * x2x * y2y +
    q21 * xx1 * y2y +
    q12 * x2x * yy1 +
    q22 * xx1 * yy1
  );
}
 
color BilinearInterpolation(color tl, color tr, color bl, color br, uint16_t w, uint16_t h, uint16_t x, uint16_t y) 
{
  // interopolate three color components respectively
  color r = (uint16_t)BilinearInterpolation(getColorR(tl), getColorR(bl), getColorR(tr), getColorR(br), 0, w, 0, h, x, y);       
  color g = (uint16_t)BilinearInterpolation(getColorG(tl), getColorG(bl), getColorG(tr), getColorG(br), 0, w, 0, h, x, y);
  color b = (uint16_t)BilinearInterpolation(getColorB(tl), getColorB(bl), getColorB(tr), getColorB(br), 0, w, 0, h, x, y);
  // then make a color based on the components
  return getColor(r, g, b);
}
// Utility implementation
#include "utils.h"

// based on: https://en.wikipedia.org/wiki/Bilinear_interpolation
float BilinearInterpolation(float q11, float q12, float q21, float q22, float x1, float x2, float y1, float y2, float x, float y) 
{
  float x2x1, y2y1, x2x, y2y, yy1, xx1;
  x2x1 = x2 - x1;
  y2y1 = y2 - y1;
  x2x = x2 - x;
  y2y = y2 - y;
  yy1 = y - y1;
  xx1 = x - x1;
  return 1.0 / (x2x1 * y2y1) * (
    q11 * x2x * y2y +
    q21 * xx1 * y2y +
    q12 * x2x * yy1 +
    q22 * xx1 * yy1
  );
}

color BilinearInterpolation(color tl, color tr, color bl, color br, uint16_t w, uint16_t h, uint16_t x, uint16_t y) 
{
  // interopolate three color components respectively
  color r = (uint16_t)BilinearInterpolation(getColorR(tl), getColorR(bl), getColorR(tr), getColorR(br), 0, w, 0, h, x, y);       
  color g = (uint16_t)BilinearInterpolation(getColorG(tl), getColorG(bl), getColorG(tr), getColorG(br), 0, w, 0, h, x, y);
  color b = (uint16_t)BilinearInterpolation(getColorB(tl), getColorB(bl), getColorB(tr), getColorB(br), 0, w, 0, h, x, y);
  // then make a color based on the components
  return getColor(r, g, b);
}

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
2213 words
Last Post: Interview Coding Exercise - Nested String (Python)
Next Post: Coding Exercise - Sort Letters by Case (C++)

The Permanent URL is: The Colour Chart Generator in C++

Leave a Reply