Skip to content

Add Jarvis March in C#. #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 6, 2018
Merged

Add Jarvis March in C#. #85

merged 7 commits into from
May 6, 2018

Conversation

june128
Copy link
Member

@june128 june128 commented Apr 19, 2018

ToDo

  • Simplify name of Run-method.
  • Make the static class Jarvis March non static.
  • Add Scalar product method to vector.
  • Make vector a struct.
  • Make properties of vector readonly.
  • Overload operators for Vector.
  • Refactor code and make it simpler.
  • Override the Equals and the GetHashCode method for Vector.
  • Discuss stuff.
  • Improve explanation of IsLeftOf.
  • Remove redundant operators.
  • Don't remove points / simplify code.


namespace JarvisMarch
{
public class Vector
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this a struct and drop the properties. It has better performance and the properties are completely superfluous for a Vector type:

public struct Vector
{
    public int X;
    public int Y;

    public Vector(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

var secondVector = new Vector(points[i].X - currentPoint.X, points[i].Y - currentPoint.Y);

// Calculate the current scalar product.
var tempScalarProduct = (firstVector.X * secondVector.X) + (firstVector.Y * secondVector.Y);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make a dot product method on the vector. Similarly for the used operators (minus) in this case. That way this could look like:

var secondVector = points[i] - currentPoint;
var tempScalarProduct = firstVector.Dot(secondVector);

{
// Search for next Point.
// Set the first vector, which is currentPoint -> previousPoint.
var firstVector = new Vector(previousPoint.X - currentPoint.X, previousPoint.Y - currentPoint.Y);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not the biggest fan of this naming. First, the Point and Vector suffix is pretty redundant. Second, firstVector means nothing. I'll have to read the Jarvis march algorithm again to come up with a better name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is not the best, I agree. But I don't know, if getting rid of Point and Vector is the best. I think they provide quite some clarity. If better names were used tho, the suffix might be redundant. I have to think about the names.


public static class JarvisMarch
{
public static List<Vector> RunJarvisMarch(List<Vector> points)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant naming:

JarvisMarch.Run(...);

is pretty self-explanatory. If you want to follow best practices then don't make these static classes. That way you could potentially implement an interface IGiftWrapping and have multiple algorithms that you can swap out at runtime (static classes/methods make this impossible)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just use normal classes in this case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah

public static List<Vector> RunJarvisMarch(List<Vector> points)
{
// Set the intial point to the first point of the list.
var initialPoint = points[0];
Copy link
Contributor

@zsparal zsparal Apr 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have a shared library somewhere in the AAA for example with List/IEnumeable extensions methods (similarly for other languages that need it). These lines just take up a bunch of space in the implementation when by all rights it should just be:

var iniitalPoint = points.MinBy(p => p.X);

We should talk about @leios about it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is somewhat related to #69, but I am not sure about the best way to do this in practice.

This is actually why the language choice chapter exists. The hope was to introduce any extra libraries and such people would need to use the language for the purpose of this book, while also benchmarking the languages against each other so people could see their strengths and weaknesses.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's something to discuss.

@june128
Copy link
Member Author

june128 commented Apr 22, 2018

Thanks for the review @Gustorn ! I will target your reviews in the following days as well :)

@june128
Copy link
Member Author

june128 commented Apr 22, 2018

I added a ToDoList for this PR.

@june128 june128 added the Implementation This provides an implementation for an algorithm. (Code and maybe md files are edited.) label Apr 28, 2018
@june128 june128 assigned june128 and unassigned june128 Apr 28, 2018
{
public struct Vector
{
public readonly int x;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Public fields should be Pascal case

// Set the first vector, which is currentPoint -> previousPoint.
var firstVector = previousPoint - currentPoint;

Vector? nextPoint = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation feels a bit unelegant

@june128 june128 added Implementation Edit This provides an edit to an algorithm implementation. (Code and maybe md files are edited.) and removed Implementation Edit This provides an edit to an algorithm implementation. (Code and maybe md files are edited.) labels Apr 29, 2018
}

// Returns true, if p is more left than b, if viewed from a.
private bool IsLeftOf(Vector a, Vector b, Vector p)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does someone know better names for this parameters? And should I provide a more in-depth explanation of what the method does?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is incorrect. It returns true if p is left of the line defined by a and b.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it's somewhat correct, but far from perfect. I'll change it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see it. It's incorrect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you were right, it's technically correct. I still think it's better to use more rigorous terms when defining operations like this.

public static bool operator==(Vector a, Vector b) => a.Equals(b);
public static bool operator!=(Vector a, Vector b) => !(a == b);
public static Vector operator+(Vector a, Vector b) => new Vector(a.x + b.x, a.y + b.y);
public static Vector operator-(Vector a, Vector b) => new Vector(a.x - b.x, a.y - b.y);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we leave those operators in here (- and +). They are nice to have, but not necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they're not used I say remove them

// Set the intial point to the point of the list, where the x-position is the lowest.
var initialPoint = points.Aggregate((leftmost, current) => leftmost.x < current.x ? leftmost : current);

convexHull.Add(initialPoint);
Copy link
Contributor

@zsparal zsparal May 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just move this inside the do-while loop (at the start), it doesn't need to be special cased

});

convexHull.Add(nextPoint);
points.Remove(nextPoint);
Copy link
Contributor

@zsparal zsparal May 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to remove the point if we don't care about collinear points (and the consensus was that we don't). There are some other reasons why you shouldn't have it here:

  1. It kind of messes with the complexity of the algorithm. It won't affect big O notation but you're adding another linear search.
  2. It's very bad manners to modify an incoming parameter

If you do want to remove the point add something like:

var remainingPoints = new HashSet<Vector>(points);

And change stuff to use that one. But again, removing the point isn't necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I removed the point from the points we search, since that point isn't needed anymore and won't be used anyway. But you're right with the linear search, it creates a bigger disadvantage than advantage... The question is tho, if I should go for the HashSet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just not remove the points

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I just exclude that now.

return potentialNextPoint;
});

convexHull.Add(nextPoint);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said in the other comment, you can just move this to the beginning and then you don't need the Add outside of the do...while loop

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Add and the other one are in there, since the output should include the start/end-point at the beginning and at the end. If we don't want that, we can just move one Add at the beginning and remove the other one like you said.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's very useful to include the starting point in the output. It doesn't really give you anything and it makes the algorithm a bit harder to read.

Copy link
Contributor

@zsparal zsparal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I think it's ready to be merged

@leios leios merged commit d27b044 into algorithm-archivists:master May 6, 2018
@leios
Copy link
Member

leios commented May 6, 2018

Thanks for all the work on this guys!

@june128 june128 deleted the addJarvisMarchCSharpPR branch May 6, 2018 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Implementation This provides an implementation for an algorithm. (Code and maybe md files are edited.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants