public void GenerateUVSphere(float parallels, float meridians)
{
ObjectVertex top = null, bottom = null;
var vertices = new ObjectVertex[(int)Ceiling(parallels) - 1, (int)Ceiling(meridians)];
for (int parallel = 0; parallel < parallels + 1; parallel++)
{
double p = parallel * (PI / parallels);
for (int meridian = 0; meridian < meridians; meridian++)
{
double m = 2 * meridian * (PI / meridians);
float x = (float)(Sin(p) * Cos(m));
float y = (float)Cos(p);
float z = (float)(Sin(p) * Sin(m));
var vertex = new ObjectVertex(x, y, z);
if (parallel <= 0)
top = vertex;
else if (parallel >= parallels)
bottom = vertex;
else
vertices[parallel - 1, meridian] = vertex;
}
}
for (int parallel = 0; parallel < parallels; parallel++)
{
for (int meridian = 0; meridian < meridians; meridian++)
{
bool last = meridian >= meridians - 1;
if (parallel <= 0)
{
var a = vertices[parallel, meridian];
var b = vertices[parallel, last ? 0 : meridian + 1];
Faces.Add(new ObjectFace(this, top, b, a));
}
else if (parallel >= parallels - 1)
{
var a = vertices[parallel - 1, meridian];
var b = vertices[parallel - 1, last ? 0 : meridian + 1];
Faces.Add(new ObjectFace(this, bottom, a, b));
}
else
{
var a = vertices[parallel - 1, meridian];
var b = vertices[parallel - 1, last ? 0 : meridian + 1];
var c = vertices[parallel, meridian];
var d = vertices[parallel, last ? 0 : meridian + 1];
AddQuad(a, b, c, d, false);
}
}
}
}
10 April 2019
Math - Generate a UV sphere
27 January 2019
Math - Calculate the 2D window position of a 3D vector
I render a 3D model as points in a viewport with OpenGL. I want to select points by clicking them. To do this, I calculate the position of the 3D point on the 2D window the same way the shader does. These variables are needed:
- Vector4 vector: the 3D position in object space of the point + it's W component. W is always 1 in object space, but gets transformed by the projection matrix. It is then used for the perspective divide.
- Matrix projection and camera (also called modelview): the matrices used to transform from object space to world space and then to 2D clip coordinates.
- Rectangle viewport: the position and size of the viewport on which to project.
- Point mouse: the window position of the mouse click. You get this point directly from the event raised by the operating system.
From then, it's actually not that hard. You do need a method to multiply matrices.
public Point GetPosition(Vector4 vector)
{
var p = Projection * Camera * vector;
//Perspective divide.
p.X /= p.W;
p.Y /= p.W;
//Scale from [-1; 1] to viewport dimensions.
p.X = (p.X + 1).Scale(2, viewport.Width);
p.Y = -(p.Y - 1).Scale(2, viewport.Height); //For OpenGL, the bottom is the origin.
//Adjust to the viewport's position on the window.
return new Point((int)p.X + viewport.Left, (int)p.Y + viewport.Top);
}
var pos = GetPosition(vector);
IsSelected = pos.X.Between(mouse.X - 5, mouse.X + 5) && pos.Y.Between(mouse.Y - 5, mouse.Y + 5);
See also
Calculate the 3D world position of a 2D window vector10 August 2018
.NET - HTTP server with TcpListener
HttpServer class
private TcpListener Listener { get; set; }
public void Listen()
{
Listener = new TcpListener(IPAddress.Any, 2000);
Listener.Start();
while (true)
{
var client = Listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem((state) => Handle(client)); //Handle each request on it's own thread.
}
}
private void Handle(TcpClient client)
{
using (var io = client.GetStream())
using (var reader = new StreamReader(io))
using (var writer = new StreamWriter(io))
{
//Request
string[] line = reader.ReadLine()?.Split(); //Do not read to end! It would hang.
string method = line[0]; //GET, POST, ...
string url = line[1]; //The requested URL.
//Response
string content = "<html><body>EGS</body></html>";
writer.WriteLine("HTTP/1.1 200 OK");
writer.WriteLine("Content-Type: text/html; charset=UTF-8");
writer.WriteLine($"Content-Length: {content.Length}");
writer.WriteLine("Connection: close");
writer.WriteLine();
writer.WriteLine(content);
}
client.Close();
}
Start the server
Server = new HttpServer(); new Thread(new ThreadStart(Server.Listen)).Start(); //On a separate thread, so the UI doesn't hang.
10 July 2018
C# - Retrieve objects from a database
public IEnumerableRetrieve (string query, params object[] parameters) where T : class { using (var connection = new OdbcConnection(ConnectionString)) using (var command = new OdbcCommand(query, Connection)) { SetParameters(command, parameters); using (var reader = command.ExecuteReader()) { var data = new List (); var columns = new HashSet (); while (reader.Read()) { if (columns.Count <= 0) for (int i = 0; i < reader.FieldCount; i++) columns.Add(reader.GetName(i)); var item = Activator.CreateInstance (); foreach (var prop in typeof(T).GetProperties()) { if (!columns.Contains(prop.Name)) continue; object value = reader[prop.Name]; if (value == null || value == DBNull.Value) { if (!prop.IsNullable()) prop.SetValue(item, default(T)); continue; } prop.SetValue(item, reader[prop.Name]); } data.Add(item); } return data; } } }
09 July 2018
Extension - Create an enumerable from an object
////// Takes an object af any type, and returns a list of that type with the object as it's first item. /// public static IEnumerableToEnumerable (this T firstItem) => firstItem == null ? new List (0) : new List (1) { firstItem };
19 March 2018
XAML - markup extensions
Recently, I wanted to pass a boolean parameter to a value converter, but whatever you put there is passed as a string. That's when I discovered markup extensions. They allow you to pass a custom class with properties of any type to the value converter. This class is something like this:
sealed class BoolMarkupExtension : MarkupExtension
{
public bool Value { get; set; }
public BoolMarkupExtension() { }
public BoolMarkupExtension(bool value)
{
Value = value;
}
public override object ProvideValue(IServiceProvider serviceProvider) => Value;
}
The value converter will receive what the ProvideValue method returns as parameter, so you can send the property or the class itself if it has multiple properties.
The value converter parameter can now be set to this class:
Visibility="{Binding IsPlaying, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter={converters:BoolMarkup true}}"
01 February 2018
C# – Passing method delegates as arguments.
I wanted to pass a method to execute to a helper method that created a response on API requests. If the method succeeded, it should return it's result; if an exception was thrown, it should return a 500 with the error. This is what I came up with:
/// <summary>
/// For methods that don't have a return value.
/// </summary>
protected HttpResponseMessage Respond(HttpRequestMessage request, Action method,
HttpStatusCode errorStatusCode, string errorMessage)
{
try
{
method();
return request.CreateResponse(HttpStatusCode.OK);
}
catch
{
return request.CreateErrorResponse(errorStatusCode, errorMessage);
}
}
/// <summary>
/// For methods that do have a return value.
/// </summary>
protected HttpResponseMessage Respond(HttpRequestMessage request, Func method,
HttpStatusCode errorStatusCode, string errorMessage)
{
try
{
return request.CreateResponse(HttpStatusCode.OK, method());
}
catch
{
return request.CreateErrorResponse(errorStatusCode, errorMessage);
}
}
Now, I can respond to an API request in a single line:
return Respond(Request, () => Repo.Update(c), HttpStatusCode.InternalServerError, "Failed!");