Testing if two objects are equal - c#

I'm trying to create a find method from scratch to see if two objects are equal given that the results of certain methods are equal, using the Equals method to do so. I know using the Find/Contains methods would be faster, but I'm not allowed use them. The signature of the method is "static int Find(List c, Coffee x)" Find seeks x in c and returns a valid index (e.g., 0, 1) if x exists in c, returns -1 otherwise. The equals method must be used to determine equivalency. If the passed object isn't equal to an object currently in the list, it is added to the list (the list contains two types of objects that derive from a base class, so the list can store both types). Equivalency is defined by name, cost, demand, holding cost(h) and roasttype(M) for regular and name, cost, demand, holding cost(h) and minimum quantity(also M) for decaf. Here's what I have so far (it's a lot of code that could probably be written better):
class EOQCalculator4
{
static void Main(string[] args)
{
// Create objects and references
Coffee obv = new Coffee();
Decaf decafCoffee = null;
Regular regularCoffee = null;
List<Coffee> inventory = new List<Coffee>();
// Prompt user for input and store it as a string
Console.Write("Enter q to quit or the whole data as a comma delimited string using the following format Name,D,C,D:minQ or R:roast ");
string s = Console.ReadLine();
// Loop
while (!s.ToLower().Equals("q"))
{
// Split string up and assign componets to variables
string[] values = s.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
string name = values[0];
string demand = (values[1]);
string cost = (values[2]);
string type = values[3];
// Check for > 0 and convert to numbers
float D = CheckDemand(demand);
float C = CheckCost(cost);
float M = 0;
if (type.StartsWith("D:"))
{
type = Regex.Match(type, #"\d+").Value;
M = CheckMin(type);
decafCoffee = new Decaf(name, D, C, M);
inventory.Add(decafCoffee);
}
else if (type.StartsWith("R:"))
{
if (type.Contains("light"))
{
M = 1;
regularCoffee = new Regular(name, D, C, M);
inventory.Add(regularCoffee);
}
else if (type.Contains("medium"))
{
M = 2;
regularCoffee = new Regular(name, D, C, M);
inventory.Add(regularCoffee);
}
else if (type.Contains("dark"))
{
M = 3;
regularCoffee = new Regular(name, D, C, M);
inventory.Add(regularCoffee);
}
else Console.WriteLine("\nError, please enter all lower case \"dark\", \"medium\", or \"light\" next time.");
}
else Console.WriteLine("\nError, please enter either \"D:\" followed by a number or \"R:\" followed by roast type next time.");
Console.Write("\nEnter q to quit or the whole data as a comma delimited string using the following format Name,D,C,D:minQ or R:roast: ");
s = Console.ReadLine();
} // End loop
// Sort and display values
var sortedList = inventory.OrderBy(i => i.Q()).ToList();
Console.WriteLine("\nName \t C ($) Demand \t Detail Q(lbs.) TAC ($) T(weeks) ");
for (int j = 0; j < inventory.Count; j++)
{
Console.WriteLine("{0}", sortedList[j].toString());
}
Console.WriteLine(obv.toStringQ());
}
#region CheckMethods
// Data validation methods
public static float CheckDemand(String R)
{
float number;
while (!float.TryParse(R, out number) || number <= 0)
{
Console.Write("Please enter a number greater than 0 for demand: ");
R = Console.ReadLine();
} return number;
}
public static float CheckCost(String R)
{
float number;
while (!float.TryParse(R, out number) || number <= 0)
{
Console.Write("Please enter a number greater than 0 for cost: ");
R = Console.ReadLine();
} return number;
}
public static float CheckMin(String R)
{
float number;
while (!float.TryParse(R, out number) || number <= 0)
{
Console.Write("Please enter a number greater than 0 for minimum quantity: ");
R = Console.ReadLine();
} return number;
}
public class Coffee
{
// Members
private static float sumQ = 0;
private static int mcount;
private float k = 20;
private float mc;
private string mName;
private float md;
private float q;
private float mh;
private float tac;
private float min = 0;
private float type = 0;
Coffee i = new Coffee();
public override bool Equals(object obj)
{
if (obj is Coffee)
{
bool isNameEqual = i.Name.Equals(this.Name);
bool isuCostEqual = i.Cost.Equals(this.Cost);
bool isDemandEqual = i.Demand.Equals(this.Demand);
bool ishCostEqual = i.h.Equals(this.h);
bool isMinEqual = i.getMin.Equals(this.min);
return (isNameEqual && isuCostEqual && isDemandEqual && ishCostEqual && isMinEqual);
}
return false;
}
// Default Constructor
public Coffee()
{ mcount = 0; }
// Full Constructor
public Coffee(string Name, float d, float c, float m)
{
mName = Name;
md = d;
mc = c;
mh = (float).30 * mc;
type = m;
min = m;
mcount++;
}
public Coffee(string Name, float d, float c)
{
mName = Name;
md = d;
mc = c;
mh = (float).30 * mc;
mcount++;
}
// Copy Constructor
public Coffee(Coffee e)
{
this.mName = e.mName;
this.md = e.md;
this.mh = e.mh;
this.mc = e.mc;
this.q = e.q;
mcount++;
}
// Destructor
~Coffee()
{ mcount--; }
// Properties
#region Properties
public float getMin
{
get { return min; }
}
public float getType
{
get { return type; }
}
public string Name
{
get { return mName; }
}
public float h
{
get { return mh; }
}
public float Cost
{
get { return mc; }
}
public float Demand
{
get { return md; }
}
public float getQ
{
get { return q; }
}
public float K
{
get { return k; }
}
public float getSumQ
{
get { return sumQ; }
set { sumQ = value; }
}
#endregion
// Methods
public virtual float Q()
{
q = (float)Math.Sqrt(2 * md * k / mh);
sumQ += q;
return q;
}
public virtual float TAC()
{
tac = q / 2 * mh + md * k / q + md * mc;
return tac;
}
public virtual float T()
{
float t = (q / (md / 52));
return t;
}
public virtual string toString()
{
string a = String.Format("{0,-10:s} {1,-10:f2} {2,-13:f0} {3,-11:f0} {4,-11:f2} {5,-0:f2}", mName, mc, md, Q(), TAC(), T());
return a;
}
public virtual string toStringQ()
{
string c = String.Format("\nIf you purchase all of the coffee you will need space to hold {0,-0:f2} of coffee", sumQ);
return c;
}
}
}
public class Decaf : Coffee
{
// Members
private float k = 30;
private float min;
private float q;
// Constructor
public Decaf(string Name, float d, float c, float m)
: base(Name, d, c)
{
min = m;
}
// Methods
public override float Q()
{
q = (float)Math.Sqrt(2 * Demand * k / h);
if (q < min)
{
return min;
}
else return q;
}
public override float TAC()
{
getSumQ += Q();
return Q() / 2 * h + Demand * k / Q() + Demand * Cost;
}
public override float T()
{
return (Q() / (Demand / 52));
}
public override string toString()
{
string a = String.Format("{0,-11:s}{1,-11:f2}{2,-12:f0}{3,-9:f0}{4,-12:f0}{5,-13:f2}{6,-10:f2}", Name, Cost, Demand, min, Q(), TAC(), T());
return a;
}
}
}
// Enumerator
[Flags] enum RoastType { light = 1, medium = 2, dark = 3 }
public class Regular : Coffee
{
// Members
RoastType roast;
private float q;
private float k = 20;
// Constructor
public Regular(string Name, float d, float c, float r)
: base(Name, d, c)
{
int x = (int) r;
roast = (RoastType) x;
roast.ToString();
}
// Methods
public override float Q()
{
q = (float)Math.Sqrt(2 * Demand * k / h);
return q;
}
public override float TAC()
{
getSumQ += Q();
return Q() / 2 * h + Demand * k / Q() + Demand * Cost;
}
public override float T()
{
return (Q() / (Demand / 52));
}
public override string toString()
{
string b = String.Format("{0,-11:s}{1,-11:f2}{2,-12:f0}{3,-9:s}{4,-12:f0}{5,-13:f2}{6,-10:f2}", Name, Cost, Demand, roast.ToString(), Q(), TAC(), T());
return b;
}
}
}
Assuming I implemented the equals method correctly, where/how would I implement the "static int Find(List<Coffee> c, Coffee x)" method?

As it stands your overridden Equals method won't work correctly. Equals tests for reference equality i.e. if two object references point to the same object. See MSDN for more info on Equals.
If you are just wanting to make sure that the same two coffees (with the same name, demand cost and type) are not added, then you can perform a simple value check on those fields, something like (method added to your Coffee class)
public bool CoffeeIsSame(Coffee c2)
{
return (this.Name == c2.Name) && (this.Demand == this.Demand) && (this.Cost == c2.Cost) && (this.Type == c2.Type);
}
Your Find method could look something like this:
static bool Find(List c, Coffee x)
{
bool result = false;
foreach(Coffee coffee in c)
{
result = coffee.CoffeeIsSame(x);
if (result)
{
break;
}
}
return result;
}
To implement your static Find method, you could add it to your Coffee class. Then you call it like this (using some of your code from your Main method as an example):
...
else if (type.Contains("dark"))
{
M = 3;
regularCoffee = new Regular(name, D, C, M);
if (!Coffee.Find(inventory, regularCoffee))
{
inventory.Add(regularCoffee);
}
}
...
Hope that helps,
cheers

Related

How to get random int values to a prefab which is called multiple times(without repeating same value)?

I have created a prefab which contains text (a*b=) and input field (to get user's answer). and I am calling this prefab 5 times using c# script. I have assigned a & b to random.range(1,10) so i can get 5 different sums. but in my case i am getting same values to all 5 sums.
I tried foreach loop and it is getting random numbers out of given range and on clicking check button it shows even correct answers in red(as incorrect).
This is the first time i am dealing with calling prefab multiple times via script. so need some help to solve it please.
TestModeQuestionUI.cs
using Helper.Keyboard;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class TestModeQuestionUI : MonoBehaviour
{
internal RectTransform refRectTransform;
[SerializeField]
TextMeshProUGUI valueA; // valueB;
[SerializeField]
MyInputField AnswerInputField;
internal int id;
internal Action<TestModeQuestionUI> onSubmitValueOfInputFieldAction;
internal Action<TestModeQuestionUI> onSelectInputFieldAction;
Color defaultColorOfAnswer = new Color(0.19f, 0.19f, 0.19f, 1f);
Color correctColorOfAnswer = new Color(0f, 0.44f, 0f, 1f);
Color incorrectColorOfAnswer = new Color(1f, 0f, 0f, 1f);
public static TestModeQuestionUI curSelectedAnswerInputField;
//-------------------------------------------------------------------------
void Awake()
{
refRectTransform = GetComponent<RectTransform>();
}
private void SetNextAnswerInputFieldAsSelected(TestModeQuestionUI
curSelectedAnswerInputField)
{
throw new NotImplementedException();
}
public void SetQuestionLabel(string v)
{
valueA.text = v;
}
public void ActiveAnswerInputField(bool active)
{
AnswerInputField.gameObject.SetActive(active);
}
public int GetAnswerInputField()
{
int result = -1;
int.TryParse(AnswerInputField.textComponent.text, out result);
return result;
}
public void SetAnswerInputField(string msg)
{
AnswerInputField.textComponent.text = msg;
}
public void SelectAnswerInputField()
{
DeSelectCurSelectedAnswerInputField();
AnswerInputField.ActivateInputField();
curSelectedAnswerInputField = this;
}
public static void DeSelectCurSelectedAnswerInputField()
{
if (curSelectedAnswerInputField != null)
{
curSelectedAnswerInputField.AnswerInputField.DeactivateInputField();
}
curSelectedAnswerInputField = null;
}
public void SetResultOfAnswerInputField(int result)
{
switch (result)
{
//==================================
// Default Color For Answer Has Not Checked
case 0:
AnswerInputField.textComponent.color = defaultColorOfAnswer;
break;
//==================================
// Correct Color For Answer Has Checked Correct
case 1:
AnswerInputField.textComponent.color = correctColorOfAnswer;
break;
//==================================
// Incorrect Color For Answer Has Checked Incorrect
case 2:
AnswerInputField.textComponent.color = incorrectColorOfAnswer;
break;
}
}
public void OnSelectInputField()
{
//Debug.Log("On Select : " + id);
if (curSelectedAnswerInputField != this)
DeSelectCurSelectedAnswerInputField();
curSelectedAnswerInputField = this;
if (onSelectInputFieldAction != null)
onSelectInputFieldAction(this);
}
public void OnSubmitValueOfInputField()
{
if (onSubmitValueOfInputFieldAction != null)
onSubmitValueOfInputFieldAction(this);
}
}
TestModeManager.cs
public class TestModeManager : MonoBehaviour
{
public static TestModeManager instance;
[SerializeField]
GameObject refTestModeQuestionExampleParent;
[SerializeField]
GameObject refTestModeQuestionExamplePrefab;
[SerializeField]
GameObject checkButton;
[SerializeField]
GameObject nextButton;
private int a, b;
List<TestModeQuestionUI> testModeQuestionExampleList;
void Start()
{
CreateUI();
}
void Update()
{
#if UNITY_EDITOR
if (Input.GetKeyDown(KeyCode.KeypadEnter))
{ SetNextAnswerInputFieldAsSelected(TestModeQuestionUI.curSelectedAnswerInputField);
}
#endif
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Keyboard.instance.gameObject.activeInHierarchy)
Keyboard.Close();
else
Application.Quit();
}
}
void CreateUI()
{
GameObject _GO;
TestModeQuestionUI _TestModeQuestionUIRefrence;
if (testModeQuestionExampleList == null)
testModeQuestionExampleList = new List<TestModeQuestionUI>();
// a = UnityEngine.Random.Range(1, 20);
// b = UnityEngine.Random.Range(1, 10);
for (int id = 1; id <= 5; id++)
{
_GO = Instantiate(refTestModeQuestionExamplePrefab,
refTestModeQuestionExampleParent.transform);
_GO.name = "TestModeQuestion Example " + id;
_TestModeQuestionUIRefrence = _GO.GetComponent<TestModeQuestionUI>
();
_TestModeQuestionUIRefrence.id = id;
_TestModeQuestionUIRefrence.onSubmitValueOfInputFieldAction =
SetNextAnswerInputFieldAsSelected;
testModeQuestionExampleList.Add(_TestModeQuestionUIRefrence);
}
ResetUI();
}
void ResetUI()
{
// Reset Multiplication Examples
a = UnityEngine.Random.Range(1, 10);
b = UnityEngine.Random.Range(1, 10);
foreach (TestModeQuestionUI _TestModeQuestionUIRefrence in
testModeQuestionExampleList)
{
_TestModeQuestionUIRefrence.SetQuestionLabel(a + " " + b + " = ");
//loop to get 5 different sums
var questions = GameObject.FindGameObjectsWithTag("question");
foreach (var question in questions)
{
// a++;
//b++;
}
}
//==================================
// Set First Answer Input Field As Selected
SetNextAnswerInputFieldAsSelected();
}
void SetNextAnswerInputFieldAsSelected(TestModeQuestionUI _
TestModeQuestionUIRefrence = null)
{
if (_TestModeQuestionUIRefrence == null)
{
//==================================
// Get First Input Field And Set As Selected
_TestModeQuestionUIRefrence = GettestModeQuestionExampleList(1);
if (_TestModeQuestionUIRefrence != null)
_TestModeQuestionUIRefrence.SelectAnswerInputField();
}
else
{
//==================================
// Get Next Input Field And Set As Selected
_TestModeQuestionUIRefrence =
GettestModeQuestionExampleList(_TestModeQuestionUIRefrence.id + 1);
if (_TestModeQuestionUIRefrence != null)
_TestModeQuestionUIRefrence.SelectAnswerInputField();
else
{
Keyboard.Close();
StartCoroutine(highlighCheckButton());
}
}
}
TestModeQuestionUI GettestModeQuestionExampleList(int id)
{
foreach (TestModeQuestionUI _TestModeQuestionUIRefrence in
testModeQuestionExampleList)
{
if (_TestModeQuestionUIRefrence.id == id)
{
return _TestModeQuestionUIRefrence;
}
}
return null;
}
IEnumerator EnableKeyboardAfterSometime(float time)
{
yield return new WaitForSeconds(time);
Keyboard.Open();
}
IEnumerator highlighCheckButton()
{
checkButton.transform.localScale = new Vector3(1f, 1f, 1f);
float animtionTime = 0.3f;
float scaleUpTo = 1.2f;
for (int i = 0; i < 4; i++)
{
yield return AnimationController.animate(scaleCheckButton,
animtionTime, 1f, scaleUpTo);
yield return AnimationController.animate(scaleCheckButton,
animtionTime, scaleUpTo, 1f);
}
checkButton.transform.localScale = new Vector3(1f, 1f, 1f);
}
void scaleCheckButton(float value)
{
checkButton.transform.localScale = new Vector3(value, value, value);
}
public void CheckButton()
{
int answer;
foreach (TestModeQuestionUI _TestModeQuestionUIRefrence in
testModeQuestionExampleList)
{
answer = _TestModeQuestionUIRefrence.GetAnswerInputField();
if ((a * b) == answer)
{
_TestModeQuestionUIRefrence.SetResultOfAnswerInputField(1);
}
else
{
_TestModeQuestionUIRefrence.SetResultOfAnswerInputField(2);
}
}
checkButton.SetActive(false);
nextButton.SetActive(true);
}
public void NextButton()
{
ResetUI();
nextButton.SetActive(false);
}
You should get the random value inside the loop, otherwise you get the same values.
foreach (TestModeQuestionUI _TestModeQuestionUIRefrence in testModeQuestionExampleList)
{
int a = UnityEngine.Random.Range(1, 10);
int b = UnityEngine.Random.Range(1, 10);
_TestModeQuestionUIRefrence.SetQuestionLabel(a, b);
}
You also should save a and b in TestModeQuestionUI because they are different betweent instances.
public class TestModeQuestionUI : MonoBehaviour
{
private int a, b;
public void SetQuestionLabel(int a, int b)
{
this.a = a;
this.b = b;
valueA.text = a + " " + b + " = ";
}
}
You have a lot of UI stuff but if i were you and if i do not want to get duplicates i would create a separate script for getting random values like this:
public class RandomIntegers {
private static List<int> myNumbersA = new List<int>();
private static List<int> myNumbersB = new List<int>();
public static void RandomValues(out int a,out int b)
{
if (myNumbersA.Count == 0)
{
for (int i = 0; i < 10; i++)
{
myNumbersA.Add(i + 1);
myNumbersB.Add(i + 1);
}
}
int indexA = Random.Range(0, myNumbersA.Count);
int indexB = Random.Range(0, myNumbersB.Count);
a = myNumbersA[indexA];
b = myNumbersB[indexB];
myNumbersA.RemoveAt(indexA);
myNumbersB.RemoveAt(indexB);
}
}
Then in your ResetUI function you can call this function using
RandomIntegers.RandomValues(out a,out b); The reason why i implemented it this way is instances of your prefab can access it when they are instantiated and since it is static you will not get same random results for a and b. But lets say you might get 6 for a and 8 for b but also 8 for a and 6 for b both will result as 48 at the end.

OOP approach for the Triangle Check scenario

Recently I had a practical test for Software developer position , in that test they asked following question.
Write me a function that receives three integer inputs for the lengths
of the sides of a triangle and returns one of four values to determine
the triangle type (1=scalene, 2=isosceles, 3=equilateral, 4=error)
Also they asked to use enums and OOP approach for this solution,
but without OOP approach I built that on following way
using System;
using System.Linq;
namespace triangleSolution
{
class Program
{
static void Main(string[] args)
{
int[] values = new int[3];
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("Please enter side " + i +" value");
values[i - 1] = Int32.Parse(Console.ReadLine());
}
Console.WriteLine(GetTriangleType(values[0], values[1], values[2]));
Console.WriteLine();
}
public enum TriangleType
{
Scalene = 1, // no two sides are the same length
Isosceles = 2, // two sides are the same length and one differs
Equilateral = 3, // all sides are the same length
Error = 4 // inputs can't produce a triangle
}
public static TriangleType GetTriangleType(int a, int b, int c)
{
// There should also be a side length check
if (a <= 0 || b <= 0 || c <= 0)
{
return TriangleType.Error;
}
if (a == b && a == c) // These could also be their own methods
{
return TriangleType.Equilateral;
}
else if (a == b || a == c || b == c)
{
return TriangleType.Isosceles;
}
else
{
return TriangleType.Scalene;
}
}
}
}
I wish to extend above solution in OOP way though I failed that interview :)
There are many ways to do this (based on the vague description)
e.g.: use a,b,c in a class Triangle that has a property TriangleType
But I have to say, the wording
Write me a function that ...
Is very misleading if OOP was what they were after.
public enum TriangleType
{
Scalene = 1, // no two sides are the same length
Isosceles = 2, // two sides are the same length and one differs
Equilateral = 3, // all sides are the same length
Error = 4 // inputs can't produce a triangle
}
public class Triangle
{
public TriangleType TriangleType {get; private set;}
public int SideA {get; private set;}
public int SideB {get; private set;}
public int SideC {get; private set;}
public Triangle(int a, int b, int c)
{
SideA = a;
SideB = b;
SideC = c;
TriangleType = GetTryangleType(a,b,c);
}
public static TriangleType GetTriangleType(int a, int b, int c)
{
// There should also be a side length check
if (a <= 0 || b <= 0 || c <= 0)
{
return TriangleType.Error;
}
if (a == b && a == c) // These could also be their own methods
{
return TriangleType.Equilateral;
}
else if (a == b || a == c || b == c)
{
return TriangleType.Isosceles;
}
else
{
return TriangleType.Scalene;
}
}
}
Usage:
static void Main(string[] args)
{
int[] values = new int[3];
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("Please enter side " + i +" value");
values[i - 1] = Int32.Parse(Console.ReadLine());
}
Triangle triangle = new Triangle(values[0], values[1], values[2]);
Console.WriteLine(triangle.TriangleType);
Console.WriteLine();
}
You could use a triangle class, something like this
public class Triangle
{
private int[] sideLength;
public Triangle(int side1, int side2, int side3)
{
sideLength = new int[3];
sideLength[0] = side1;
sideLength[1] = side2;
sideLength[2] = side3;
}
public TriangleType GetTriangleType()
{
//Your code here ;)
}
}

Invoke: how can I assign UI obj from BackgroundWorker? C#

Here is the core of my code. I've tried Invoke every which way to China, but I always get the same big red X and an ObjectDisposed exception on Form1. (Edited out unrelated code for brevity.)
using System;
using System.Globalization;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using KnownColorsPalette;
namespace Color_Visualizer
{
public partial class Form1 : Form
{
static CultureInfo m_culture = CultureInfo.CurrentCulture;
FastPixel m_fp; // FastPixel encapsulates
// Bitmap.LockBits() funcs & data
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
double fAngle, fRadius, d;
Point3D vU, vV;
Point pLocation = new Point();
do
{
m_pNormal = Coord.Plane.Normal;
fAngle = Math.Atan2(m_pNormal.y, m_pNormal.x);
fRadius = Math.Sqrt(m_pNormal.x * m_pNormal.x + m_pNormal.y * m_pNormal.y);
fAngle += fSpeed * 180 / Math.PI;
m_pNormal.x = Math.Cos(fAngle) * fRadius;
m_pNormal.y = Math.Sin(fAngle) * fRadius;
m_fp.Lock();
m_fp.Clear(Color.Black);
foreach (FoundColors fc in m_lColors.Values)
{
vU = new Point3D(Coord.U);
d = dist(fc.pt, ref vU);
vV = Coord.V;
vV.mult(d);
pLocation.X = (int)(m_midHoriz + vU.norm());
pLocation.Y = (int)(m_midVert + vV.norm());
m_fp.SetPixel(pLocation, fc.color);
}
m_fp.Unlock();
Invoke((MethodInvoker)delegate { pictureBox1.Image = m_fp.Bitmap; });
} while (true);
}
public Form1()
{
InitializeComponent();
WindowState = FormWindowState.Maximized;
CoordinateSystem.AssignMe(this);
}
void ReadColors() // I saved all of Wikipedia's 1200+ named colors
{ // as a text file.
}
private void Form1_Load(object sender, EventArgs e)
{
ReadColors();
Point3D p = new Point3D(127.5, 127.5, 127.5);
foreach (FoundColors fc in m_lColors.Values)
fc.pt = fc.color - p; // My Point3D class has
// implicit operator casts to and
// from Color.
Coord = new CoordinateSystem(new Plane(new Point3D(-127.5, -127.5, -127.5), new Point3D(-1, 0, 0)));
backgroundWorker1.RunWorkerAsync();
}
double fSpeed = 5;
Point3D m_pNormal = new Point3D();
double m_fDist, m_fDot;
public double dist(Point3D pt, ref Point3D vU)
{
double c1 = pt.dot(vU);
double c2 = vU.dot(vU);
double b = c1 / c2;
vU.mult(b);
//m_fDot = pt.dot(Coord.Normal);
m_fDist = pt.norm(pt - vU);
return m_fDist;
}
double m_midHoriz, m_midVert;
private void Form1_Resize(object sender, EventArgs e)
{
m_midHoriz = pictureBox1.Width / 2;
m_midVert = pictureBox1.Height / 2;
m_fp = new FastPixel(new Bitmap(pictureBox1.Width, pictureBox1.Height));
}
}
}
This is just support code, not central to my question:
Sorting.cs
using System.Collections.Generic;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
using KnownColorsPalette;
namespace Color_Visualizer
{
public partial class Form1 : Form
{
public static ColorComp m_compClr = new ColorComp();
public static NameComp m_compName = new NameComp();
SortedList<Color, FoundColors> m_lColors = new SortedList<Color, FoundColors>(m_compClr);
SortedList<string, FoundColors> m_lColorByName = new SortedList<string, FoundColors>(m_compName);
[DebuggerDisplayAttribute("{name}, R={color.R}, G={color.G}, B={color.B}")]
class FoundColors
{
public Color color = Color.Empty;
public string name = "";
public CIELab_Color cLab;
public Point3D pt;
public List<int> lClosest = new List<int>();
public int nFarthest;
public FoundColors(FoundColors fc)
{
color = fc.color;
name = fc.name;
cLab = new CIELab_Color(fc.cLab.CIE_L, fc.cLab.CIE_a, fc.cLab.CIE_b);
lClosest.AddRange(fc.lClosest);
nFarthest = fc.nFarthest;
}
public FoundColors() { }
}
struct sort
{
public double dist;
public int index;
public sort(double _d, int _i) { dist = _d; index = _i; }
}
class DistComp : IComparer<sort>
{
int IComparer<sort>.Compare(sort x, sort y)
{
if ((object)x == null)
if ((object)y == null)
return 0;
else
return -1;
if ((object)y == null) return 1;
if (x.dist > y.dist) return -1;
return 1;
}
}
public class NameComp : IComparer<string>
{
int IComparer<string>.Compare(string x, string y)
{
if ((object)x == null)
if ((object)y == null)
return 0;
else
return -1;
if ((object)y == null) return 1;
return x.CompareTo(y);
}
}
public class ColorComp : IComparer<Color>
{
int IComparer<Color>.Compare(Color x, Color y)
{
if ((object)x == null)
if ((object)y == null)
return 0;
else
return -1;
if ((object)y == null) return 1;
if (x.R > y.R)
return -1;
else if (x.R < y.R)
return 1;
else if (x.G > y.G)
return -1;
else if (x.G < y.G)
return 1;
else if (x.B > y.B)
return -1;
else if (x.B < y.B)
return 1;
return 0;
}
}
}
}
And lastly some more support code, CoordinateSystem.cs:
using System;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
namespace Color_Visualizer
{
public partial class Form1 : Form
{
class CoordinateSystem
{
const int MAX = 256;
const double PlaneWidth = 600;
static Form1 Me;
static Point3D axisZ = new Point3D(0, 0, 1);
static Point3D axisY = new Point3D(0, 1, 0);
private Plane m_plane = new Plane(new Point3D(128, 128, 128), new Point3D(-128, 0, 0));
private Point3D m_pV = new Point3D(0, 0, 0);
private Point3D m_pU = new Point3D(0, 0, 0);
private double m_fInc;
public CoordinateSystem(Plane axAxis)
{
m_fInc = PlaneWidth / Me.ClientSize.Height;
Plane = axAxis;
}
public static void AssignMe(Form1 form) { Me = form; }
public Point3D U { get { return m_pU; } protected set { m_pU = value; } }
public Point3D V { get { return m_pV; } protected set { m_pV = value; } }
public Point3D Normal { get { return m_plane.Normal; } set { m_plane.Normal = value; } }
static double COSerror = 0.99619469809174553229501040247389;
public Plane Plane
{
get { return m_plane; }
set {
m_plane = value;
if (m_plane.dot(axisZ) > COSerror)
U = U.cross(m_plane, axisY);
else
U = U.cross(m_plane, axisZ);
U.div(U.norm());
V = U.cross(U, m_plane);
V.div(V.norm());
}
}
}
[DebuggerDisplayAttribute("x = {x}, y = {y}, z = {z}")]
public class Point3D
{
public double x, y, z;
public Point3D(double _x, double _y, double _z) { x = _x; y = _y; z = _z; }
public Point3D(Point3D p) { x = p.x; y = p.y; z = p.z; }
public Point3D() { x = 0; y = 0; z = 0; }
public bool Equals(Point3D p) { return x == p.x & y == p.y & z == p.z; }
public override bool Equals(object obj) { return Equals((Point3D)obj); }
public static bool operator ==(Point3D p1, Point3D p2) { return p1.Equals(p2); }
public static bool operator !=(Point3D p1, Point3D p2) { return !p1.Equals(p2); }
public static Point3D operator -(Point3D e, Point3D s) { return new Point3D(e.x - s.x, e.y - s.y, e.z - s.z); }
public static Point3D operator +(Point3D e, Point3D s) { return new Point3D(e.x + s.x, e.y + s.y, e.z + s.z); }
public static Point3D operator *(double m, Point3D v) { return new Point3D(m * v.x, m * v.y, m * v.z); }
public static Point3D operator *(Point3D v, double m) { return new Point3D(v.x / m, v.y / m, v.z / m); }
public static Point3D operator /(double m, Point3D v) { return new Point3D(m * v.x, m * v.y, m * v.z); }
public static Point3D operator /(Point3D v, double m) { return new Point3D(v.x / m, v.y / m, v.z / m); }
public static implicit operator Color(Point3D p) { return Color.FromArgb((int)p.x, (int)p.y, (int)p.z); }
public static implicit operator Point3D(Color c) { return new Point3D(c.R, c.G, c.B); }
//public override int GetHashCode()
//{
// unchecked
// {
// var hash = new SpookyHash();
// hash.Update(x);
// hash.Update(y);
// hash.Update(z);
// return hash.Final().GetHashCode();
// }
//}
// dot product (3D) which allows vector operations in arguments
public double dot(Point3D u, Point3D v) { return u.x * v.x + u.y * v.y + u.z * v.z; }
public double dot(Point3D u) { return u.x * x + u.y * y + u.z * z; }
public double norm(Point3D v) { return Math.Sqrt(dot(v, v)); } // norm = length of vector
public double norm() { return Math.Sqrt(dot(this, this)); } // norm = length of vector
public double dist(Point3D u, Point3D v) { return norm(u - v); } // distance = norm of difference
public double dist(Point3D u) { return norm(this - u); }
public Point3D cross(Point3D u, Point3D v) { return new Point3D(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x); }
public Point3D cross(Point3D u) { return new Point3D(u.y * z - u.z * y, u.z * x - u.x * z, u.x * y - u.y * x); }
public void add(Point3D p) { x += p.x; y += p.y; z += p.z; }
public void mult(double m) { x *= m; y *= m; z *= m; }
public void div(double m) { x /= m; y /= m; z /= m; }
}
class Plane : Point3D
{
Point3D m_pNormal;
public Plane(Point3D pOrigin, Point3D pNormal) : base(pOrigin) { m_pNormal = pNormal; }
public Plane(Point3D p) : base(p) { }
public Plane(double x, double y, double z) : base(x, y, z) { }
public Point3D Normal { get { return m_pNormal; } set { m_pNormal = value; } }
public double PointToPlane(Point3D p) { return p.dot(Normal); }
}
private CoordinateSystem m_coordSys;
private CoordinateSystem Coord
{
get { return m_coordSys; }
set { m_coordSys = value; }
}
}
Only the 1st code segment is genuinely relevant to the question, but I know someone will ask for it, so I included much of the supporting code.
Note that I have also tried such things as diverse as the ProgressChanged event (after enabling it in Properties of course) and various forms of delegates. This use to be a fairly simple matter with old delegates, but I spent 10 hours today with no success, and I almost never fail to find working code examples, even if I have to wade thru dozens of inferior answers. There is an utter profusion of contradictory answers to this question depending on the date of the post and the kind of approach suggested.
The Invoke method does work if I immediately Thread.Sleep() for 200ms. Haven't tested the lower limit, but it won't be consistent across machines, so reporting it won't be informative.
Update this code
...
m_fp.Unlock();
var capturedBitmap = m_fp.Bitmap.Clone();
Invoke((MethodInvoker)delegate { pictureBox1.Image = capturedBitmap; });
...
You are probably getting the red x because you are modifying the bitmap as you assign it to the picture box. Clone the bitmap so you are not playing with the one in your picturebox.

How to update PictureBox from BackgroundThread?

I'm doing all my expensive calculations in a background thread and need to be able to assign pictureBox1.Image after each cycle of calculations. I use to do this using delegates, but its been a long time and things don't seem to work that way anymore.
I tried putting the assignment in a WorkerCompleted event handler, but then I can't figure out how to restart backgroundWorker1. I've been at this all day and feel enormously frustrated, this use to be so easy to do.
This is the most relevant part of the code:
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using KnownColorsPalette;
namespace Color_Visualizer
{
public partial class Form1 : Form
{
static CultureInfo m_culture = CultureInfo.CurrentCulture;
double[,][] distances = new double[3000, 3000][];
FastPixel m_fp;
public Form1()
{
InitializeComponent();
WindowState = FormWindowState.Maximized;
this.pictureBox1.LoadCompleted += new System.ComponentModel.AsyncCompletedEventHandler(PictureBox1_LoadCompleted);
CoordinateSystem.AssignMe(this);
}
private void Form1_Load(object sender, EventArgs e)
{
ReadColors(); // Reads text file alternating name and RGB hex of
// Wikipedia's 1200+ named colors.
Point3D p = new Point3D(127.5, 127.5, 127.5);
foreach (FoundColors fc in m_lColors.Values)
fc.pt = fc.color - p;
Coord = new CoordinateSystem(new Plane(new Point3D(-127.5, -127.5, -127.5), new Point3D(-1, 0, 0)));
backgroundWorker1.RunWorkerAsync();
}
double fSpeed = 5;
Point3D m_pNormal = new Point3D();
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
double fAngle, fRadius, d;
Point3D vU, vV;
Point pLocation = new Point();
m_pNormal = Coord.Plane.Normal;
fAngle = Math.Atan2(m_pNormal.y, m_pNormal.x);
fRadius = Math.Sqrt(m_pNormal.x * m_pNormal.x + m_pNormal.y * m_pNormal.y);
fAngle += fSpeed * 180 / Math.PI;
m_pNormal.x = Math.Cos(fAngle) * fRadius;
m_pNormal.y = Math.Sin(fAngle) * fRadius;
m_fp.Lock();
m_fp.Clear(Color.Black);
foreach (FoundColors fc in m_lColors.Values)
{
vU = new Point3D(Coord.U);
d = dist(fc.pt, ref vU);
vV = Coord.V;
vV.mult(d);
pLocation.X = (int)(m_midHoriz + vU.norm());
pLocation.Y = (int)(m_midVert + vV.norm());
m_fp.SetPixel(pLocation, fc.color);
}
m_fp.Unlock();
}
double m_fDist, m_fDot;
public double dist(Point3D pt, ref Point3D vU)
{
double c1 = pt.dot(vU);
double c2 = vU.dot(vU);
double b = c1 / c2;
vU.mult(b);
m_fDot = pt.dot(Coord.Normal);
m_fDist = pt.norm(pt - vU);
return m_fDist;
}
double m_midHoriz, m_midVert;
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
pictureBox1.Image = m_fp.Bitmap;
}
private void Form1_Resize(object sender, EventArgs e)
{
m_midHoriz = pictureBox1.Width / 2;
m_midVert = pictureBox1.Height / 2;
m_fp = new FastPixel(new Bitmap(pictureBox1.Width, pictureBox1.Height));
}
}
}
And this is part of my support code:
using System;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
namespace Color_Visualizer
{
public partial class Form1 : Form
{
class CoordinateSystem
{
const int MAX = 256;
const double PlaneWidth = 600;
static Form1 Me;
static Point3D axisZ = new Point3D(0, 0, 1);
static Point3D axisY = new Point3D(0, 1, 0);
private Plane m_plane = new Plane(new Point3D(128, 128, 128), new Point3D(-128, 0, 0));
private Point3D m_pV = new Point3D(0, 0, 0);
private Point3D m_pU = new Point3D(0, 0, 0);
private double m_fInc;
public CoordinateSystem(Plane axAxis)
{
m_fInc = PlaneWidth / Me.ClientSize.Height;
Plane = axAxis;
}
public static void AssignMe(Form1 form) { Me = form; }
public Point3D U { get { return m_pU; } protected set { m_pU = value; } }
public Point3D V { get { return m_pV; } protected set { m_pV = value; } }
public Point3D Normal { get { return m_plane.Normal; } set { m_plane.Normal = value; } }
static double COSerror = 0.99619469809174553229501040247389;
public Plane Plane
{
get { return m_plane; }
set {
m_plane = value;
if (m_plane.dot(axisZ) > COSerror)
U = U.cross(m_plane, axisY);
else
U = U.cross(m_plane, axisZ);
U.div(U.norm());
V = U.cross(U, m_plane);
V.div(V.norm());
}
}
}
[DebuggerDisplayAttribute("x = {x}, y = {y}, z = {z}")]
public class Point3D
{
public double x, y, z;
public Point3D(double _x, double _y, double _z) { x = _x; y = _y; z = _z; }
public Point3D(Point3D p) { x = p.x; y = p.y; z = p.z; }
public Point3D() { x = 0; y = 0; z = 0; }
public bool Equals(Point3D p) { return x == p.x & y == p.y & z == p.z; }
public override bool Equals(object obj) { return Equals((Point3D)obj); }
public static bool operator ==(Point3D p1, Point3D p2) { return p1.Equals(p2); }
public static bool operator !=(Point3D p1, Point3D p2) { return !p1.Equals(p2); }
public static Point3D operator -(Point3D e, Point3D s) { return new Point3D(e.x - s.x, e.y - s.y, e.z - s.z); }
public static Point3D operator +(Point3D e, Point3D s) { return new Point3D(e.x + s.x, e.y + s.y, e.z + s.z); }
public static Point3D operator *(double m, Point3D v) { return new Point3D(m * v.x, m * v.y, m * v.z); }
public static Point3D operator *(Point3D v, double m) { return new Point3D(v.x / m, v.y / m, v.z / m); }
public static Point3D operator /(double m, Point3D v) { return new Point3D(m * v.x, m * v.y, m * v.z); }
public static Point3D operator /(Point3D v, double m) { return new Point3D(v.x / m, v.y / m, v.z / m); }
public static implicit operator Color(Point3D p) { return Color.FromArgb((int)p.x, (int)p.y, (int)p.z); }
public static implicit operator Point3D(Color c) { return new Point3D(c.R, c.G, c.B); }
//public override int GetHashCode()
//{
// unchecked
// {
// var hash = new SpookyHash();
// hash.Update(x);
// hash.Update(y);
// hash.Update(z);
// return hash.Final().GetHashCode();
// }
//}
// dot product (3D) which allows vector operations in arguments
public double dot(Point3D u, Point3D v) { return u.x * v.x + u.y * v.y + u.z * v.z; }
public double dot(Point3D u) { return u.x * x + u.y * y + u.z * z; }
public double norm(Point3D v) { return Math.Sqrt(dot(v, v)); } // norm = length of vector
public double norm() { return Math.Sqrt(dot(this, this)); } // norm = length of vector
public double dist(Point3D u, Point3D v) { return norm(u - v); } // distance = norm of difference
public double dist(Point3D u) { return norm(this - u); }
public Point3D cross(Point3D u, Point3D v) { return new Point3D(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x); }
public Point3D cross(Point3D u) { return new Point3D(u.y * z - u.z * y, u.z * x - u.x * z, u.x * y - u.y * x); }
public void add(Point3D p) { x += p.x; y += p.y; z += p.z; }
public void mult(double m) { x *= m; y *= m; z *= m; }
public void div(double m) { x /= m; y /= m; z /= m; }
}
class Plane : Point3D
{
Point3D m_pNormal;
public Plane(Point3D pOrigin, Point3D pNormal) : base(pOrigin) { m_pNormal = pNormal; }
public Plane(Point3D p) : base(p) { }
public Plane(double x, double y, double z) : base(x, y, z) { }
public Point3D Normal { get { return m_pNormal; } set { m_pNormal = value; } }
public double PointToPlane(Point3D p) { return p.dot(Normal); }
}
private CoordinateSystem m_coordSys;
private CoordinateSystem Coord
{
get { return m_coordSys; }
set { m_coordSys = value; }
}
}
}
And more support code:
[DebuggerDisplayAttribute("{name}, R={color.R}, G={color.G}, B={color.B}")]
class FoundColors
{
public Color color = Color.Empty;
public string name = "";
public CIELab_Color cLab;
public Point3D pt;
public List<int> lClosest = new List<int>();
public int nFarthest;
public FoundColors(FoundColors fc)
{
color = fc.color;
name = fc.name;
cLab = new CIELab_Color(fc.cLab.CIE_L, fc.cLab.CIE_a, fc.cLab.CIE_b);
lClosest.AddRange(fc.lClosest);
nFarthest = fc.nFarthest;
}
public FoundColors() { }
}
The Invoke method does work if I immediately Thread.Sleep() for 200ms.
m_fp.Unlock();
this.Invoke((MethodInvoker)delegate () { pictureBox1.Image = m_fp.Bitmap; });
Thread.Sleep(200);
} while (true);
Haven't tested the lower limit, but it won't be consistent across machines, so reporting it won't be informative.
Open a new thread and create a while in of the function
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
public void DoWork()
{
while (!_shouldStop)
{
//REFRESH YOUR IMAGE
}
}

KeyNotFoundException in filled dictionary

I am trying to modify value in dictionary, but the compiler throws KeyNotFoundException. I'm sure, I declared that key in dictionary, because I am calling GenerateEmptyChunks() method, which fills dictionary with chunks with key of their position and values are empty for level generator. I've checked debugger and Chunks dictionary object is correctly filled with keys and values. Is it caused by my unworking CompareTo method? If yes, how I have modify CompareTo method to return right values?
public Dictionary<WPoint, WChunk> Chunks = new Dictionary<WPoint, WChunk>();
GenerateEmptyChunks() method:
public void GenerateEmptyChunks(int Xcount, int Ycount)
{
for(int x = 0; x <= Xcount; x++)
{
for (int y = 0; y <= Ycount; y++)
{
this.Chunks.Add(new WPoint(x, y), new WChunk(x, y));
}
}
}
AddBlock() method which is called by level generator for each tile:
public void AddBlock(WPoint location, int data)
{
this.Chunks[location.GetChunk()].AddTile(new WTile(location, data));
}
WChunk object:
public class WChunk
{
public int ChunkX;
public int ChunkY;
public SortedDictionary<WPoint, WTile> Tiles = new SortedDictionary<WPoint, WTile>();
public WChunk(int posX, int posY)
{
ChunkX = posX;
ChunkY = posY;
}
public void AddTile(WTile tile)
{
Tiles.Add(tile.GetLocation(), tile);
}
}
WPoint object:
public class WPoint : IComparable
{
public float X;
public float Y;
public WPoint(float x, float y)
{
X = x;
Y = y;
}
public WPoint GetChunk()
{
//Oprava pre bloky mensie ako (1,1)
if (X <= 16 && Y <= 16)
{
return new WPoint(0, 0);
}
else
{
double pX = (double)(X / 16);
double pY = (double)(Y / 16);
return new WPoint((int)Math.Floor(pX), (int)Math.Floor(pY));
}
}
public int CompareTo(object obj)
{
WPoint point2 = (WPoint)obj;
if (point2.X == this.X && point2.Y == this.Y)
{
return 0;
}
else if (point2.X >= this.X && point2.Y >= this.Y)
{
return -1;
}
else
{
return 1;
}
}
}
Any ideas why is compiler rejecting keys, when they are in dictionary?
Yes. You have not overridden GetHashCode.
Dictionary is using the GetHashCode and Equals for key comparisons, so implementing the IComparable interface is not enough. Have a look at this answer, that's exactly what you need.

Categories

Resources