Was a bit shocked to discover that System.Drawing.PointF appears to have operators for subtracting sizes but not other PointFs. So I'm trying to write my own PointF class, but it needs to be able to have System.Drawing.Points automatically converted to it, or it really doesn't add any convenience. So I wrote these constructors:
public PointF(float x = 0, float y = 0)
{
this.x = x;
this.y = y;
}
public PointF(System.Drawing.PointF p) : this(p.X, p.Y) { }
public PointF(System.Drawing.Point p) : this(p.X, p.Y) { }
But I'm still getting this error:
cannot convert from 'System.Drawing.Point' to 'my_namespace.PointF'
(I have a function that accepts a my_namespace.PointF but I'm passing in a System.Drawing.Point).
Shouldn't the 3rd constructor kick in and auto-convert it?
Do you have an implicit conversion defined in your my_namespace.PointF class? It won't automatically convert otherwise.
public PointF(float x = 0, float y = 0)
{
this.x = x;
this.y = y;
}
public PointF(System.Drawing.PointF p) : this(p.X, p.Y) { }
public PointF(System.Drawing.Point p) : this(p.X, p.Y) { }
//add this:
public static implicit operator PointF(System.Drawing.Point pt)
{ return new PointF(pt); }
Have you considered the option of writing an 'extension method' instead of rolling out your own class ?
You can't have operator overloading per se via extn. methods (proposed in next revision of the framework).. but you should be able to use a synonymous method called Add() for + and get by.
This compiles for me:
class PointF {
float x; float y;
public PointF(float x, float y)
{
this.x = x;
this.y = y;
}
public PointF(System.Drawing.PointF p) : this(p.X, p.Y) { }
public PointF(System.Drawing.Point p) : this(p.X, p.Y) { }
public static implicit operator PointF(System.Drawing.Point pt) { return new PointF(pt); }
public static implicit operator PointF(System.Drawing.PointF pt) { return new PointF(pt); }
}
//....
static void test(pointf.PointF p) {
}
//....
test(new System.Drawing.PointF(1, 1));
Related
I have a base class:
public class Base
{
public Base(X x ,Y y){
this.x = x;
this.y = y;
}
public X x{get;}
public Y y{get;}
}
and a deriver:
public class Derive : Base
{
public Derive(Z z, Q q) :Base (? ?)
{
}
private void ConstructXY(Z z, Q q)
{
//Advanced logic for creating an X and a Y
if(q.something == 5){
this.x = new X(28);
}
else{
this.x = new X(25);
}
if(this.x.something == 25 && q == 9){
this.y = new Y(1);
}
else{
this.y = new Y(5)
}
}
}
Now I can't correctly call the base constuctor without the "advanced" logic. I used to be able to call ConstructXY() from Derive.ctor() and set x and y from there, this is no longer valid since I removed the x and y setters. My real-life scenario contains a lot more logic so I am not willing to create a ternary mess.
You can call your "advanced" logic if it fits inside a static method
Here is an approach using Tuple available in C# 7 :
public class Base
{
// This constructor was added to avoid calling twice ConstructXY
public Base((X x, Y y) tuple) :
this (tuple.x, tuple.y)
{
}
public Base(X x, Y y)
{
this.x = x;
this.y = y;
}
public X x { get; }
public Y y { get; }
}
public class Derive : Base
{
public Derive(Z z, Q q) : base(ConstructXY(z, q))
{
}
private static (X x, Y y) ConstructXY(Z z, Q q)
{
X x;
Y y;
//Advanced logic for creating an X and a Y
if (q.something == 5)
{
x = new X(5);
}
else
{
x = new X(25);
}
if (x.something == 25 && q == 9)
{
y = new Y(1);
}
else
{
y = new Y(5)
}
return (x, y);
}
}
If you cannot change the access modifiers of X and Y in the base class so they are accessible for subclasses, then you will have to follow the contract, leaving the constructor the only possible place where you can set those members.
The only way to add more logic to calculate those values would be to use static methods, for example like this:
public class Derive : Base
{
public Derive(Z z, Q q)
: base(ConstructX(q), ConstructY(q, z))
{ }
private static X ConstructX(Q q)
{
if (q.something == 5)
return new X(28);
else
return new X(25);
}
private static Y ConstructY(Q q, Z z)
{
if (z.something == 25 && q.something == 9)
return new Y(1);
else
return new Y(5);
}
}
Since these are separate method calls, you cannot calculate both values “at once”, so you cannot make the result of Y depend on the result of X without redoing the calculation based on Z and Q again.
Another way you could solve this is by removing the public constructor on Derive altogether and provide a static factory method instead:
public class Derive : Base
{
private Derive(X x, Y y)
: base(x, y)
{ }
public static Derive Create(Z z, Q q)
{
// here you can use your original logic to calculate X and Y
X x = …
Y y = …
return new Derive(x, y);
}
}
Depending on your complexity of those calculations, this might be the better solution. If you do need the original Z and Q values, just extend the private constructor to also take those and store them as well:
private Derive(Z z, Q q, X x, Y y)
: base(x, y)
{
this.Z = z;
this.Q = q;
}
I don't really like this way of doing it and would avoid it if possible but you can use a ternary statement in your call to base:
public Derive(Z z, Q q)
: base(new X(xCondition ? 28 : 25), new Y(yCondition ? 1 : 5))
Use static methods to do the conversion. Like this.
public class Derive : Base
{
public Derive(Z z, Q q) :base (ConvertToX(z, q), ConvertToY(z, q))
{
}
private static X ConvertToX(Z z, Q q) {
if(q.something == 5){
return new X(28);
}
return new X(25);
}
private static Y ConvertToY(Z z, Q q) {
// TODO
}
}
Why not declare your base class setters as private:
public class Base
{
public Base(X x ,Y y){
this.x = x;
this.y = y;
}
public X x{get; private set;}
public Y y{get; private set;}
}
That way you can still set them in the constructor, and they would not be settable outside?
I guess, it's a pretty basic problem, but I couldn't find an answer.
Program is made for learning purpose, I'd defined a vector class with multiplication operator like this:
public class vector
{
private int x;
private int y;
public vector(int x,int y)
{
this.x = x;
this.y = y;
}
public static vector operator *(vector w1, vector w2)
{
return int w1.x*w2.x + w1.y * w2.y;
}
}
The problem is that visual studio underlines the expression in return, how should I modify the definition of "*" operator to make it work ?
You defined your function to return a vector, however you are only returning an int.
public static vector operator *(vector w1, vector w2)
{
return int w1.x*w2.x + w1.y * w2.y;
}
should be
public static int operator *(vector w1, vector w2)
{
return int (w1.x*w2.x + w1.y * w2.y);
}
Or for example, if you wanted to return a vector for the addition operator, that would look like:
public static vector operator +(vector w1, vector w2)
{
return new vector (w1.x+w2.x, w1.y + w2.y);
}
You need to return a new instance of vector, try this:
public class vector
{
private int x;
private int y;
public vector(int x, int y)
{
this.x = x;
this.y = y;
}
public static vector operator *(vector w1, vector w2)
{
return new vector(w1.x* w2.x, w1.y * w2.y);
}
}
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.
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.
I am having the following problem:
public class A {
public A(X, Y, Z) {
...
}
}
public class B : A {
public B(X, Y) : base(X, Y) {
//i want to instantiate Z here and only then pass it to the base class!
}
}
How can I solve this problem? Is there a way?
The common solution is to call a static method belonging to the type that can calculate the value of the parameter to be passed to the base constructor.
For example:
public B(int x, int y)
: base(x, y, CalculateZ(x, y))
{
}
// You can make this parameterless if it does not depend on X and Y
private static int CalculateZ(int x, int y)
{
//Calculate it here.
int exampleZ = x + y;
return exampleZ;
}
Do note that CalculateZ cannot be an instance method, because the this reference is not available in constructor initializers.
From the language-specification 10.11.1 Constructor initializers:
An instance constructor initializer
cannot access the instance being
created. Therefore it is a
compile-time error to reference this
in an argument expression of the
constructor initializer, as is it a
compile-time error for an argument
expression to reference any instance
member through a simple-name.
EDIT: Changed 'instance' to 'static' in the description.
You need to calculate Z before the constructor itself gets called. If it's simple you can use an inline expression, else you'll need to define a helper function.
Using a helperfunction:
public class A {
public A(X x, Y y, Z z) {
...
}
}
public class B : A {
private static Z calculateZ()
{
}
public B(X x, Y y) : base(X, Y, calculateZ()) {
}
}
Without helperfunction:
public B(X, Y) : base(X, Y, X+Y) {
}
public abstract class A {
public A(X, Y) {
...
}
public abstract Z TheVariableZ{get;set;}
}
public class B : A {
public B(X, Y) : base(X, Y) {
//i can only calculate Z here!
}
public override Z TheVariableZ{//implement it here}
}
And if you can't make A abstract, just mark the property as virtual
Possibly this:
public abstract class A {
public A(X, Y) {
CalculateZ();
}
abstract void CalculateZ();
}
public class B : A {
public B(X, Y) : base(X, Y) {
}
override void CalculateZ()
{
... Calculate here.
}
}