2d, mandelbrot, sketch adapted to use doubles, now doesn't work

edited April 2017 in Questions about Code

Hello, I made this mandelbrot renderer with the help of a friend, you can see it works fine: click to move/zoom https://www.dropbox.com/s/u6vql2ccmw1binb/mb2D_06.7z?dl=0

I then noticed the loss off precision when zoomed in, so today I tried to convert whatever I had to, to double precision. I made my own 2D vector class which processes double pres. values, but now everything is whacked. I can draw the circle, but when I run mandelbrot function it just makes a white screen.. here is the attempted adapted code: https://www.dropbox.com/s/8i37kmuefdbfwj0/mb2D_08.7z?dl=0

in its current state when you run it you will see a circle, my last attempt at debugging before I gave up.. for today. if anyone would mind having a look it would be really helpful. Thank you.

Answers

  • edited April 2017 Answer ✓

    https://forum.Processing.org/two/discussion/15473/readme-how-to-format-code-and-text

    Only revised your class Vec2D and made some mods on it.
    No idea whether it might work for ya now though: :-??

    // forum.Processing.org/two/discussion/22209/
    // 2d-mandelbrot-sketch-adapted-to-use-doubles-
    // now-doesn-t-work#Item_1
    
    // 2017-Apr-25
    
    static public class Vec2D implements Cloneable {
      public double x, y;
    
      public Vec2D() {
      }
    
      public Vec2D(final double n) {
        set(n, n);
      }
    
      public Vec2D(final double x, final double y) {
        set(x, y);
      }
    
      public Vec2D(final Vec2D v) {
        set(v);
      }
    
      public Vec2D set(final Vec2D v) {
        return set(v.x, v.y);
      }
    
      public Vec2D set(final double px, final double py) {
        x = px;
        y = py;
        return this;
      }
    
      public Vec2D add(final Vec2D v) {
        return set(x + v.x, y + v.y);
      }
    
      public Vec2D sub(final Vec2D v) {
        return set(x - v.x, y - v.y);
      }
    
      public Vec2D mul(final Vec2D v) {
        return set(x * v.x, y * v.y);
      }
    
      public Vec2D mul(final double n) {
        return set(x * n, y * n);
      }
    
      public Vec2D div(final Vec2D v) {
        return set(x / v.x, y / v.y);
      }
    
      public Vec2D div(final double n) {
        return set(x / n, y / n);
      }
    
      public double magSq() {
        return x*x + y*y;
      }
    
      public double mag() {
        return Math.sqrt(magSq());
      }
    
      @ Override public Vec2D clone() {
        try {
          return (Vec2D) super.clone();
        } 
        catch (final CloneNotSupportedException ex) {
          throw new RuntimeException(ex);
        }
      }
    
      @ Override public String toString() {
        return "[ " + x + ", " + y + " ]";
      }
    }
    
  • hello! I replaced the class with your revised version. This totally works now. But the syntax and stuff you have used is confounding. I don't understand the concept of using final as a type for the input in the class functions.

    I am curious, what is the reason for the "set" functions

              public Vec2D set(final Vec2D v) {
                return set(v.x, v.y);
              }
             
              public Vec2D set(final double px, final double py) {
                x = px;
                y = py;
                return this;
              }
    

    e.g. you define a new Vec2D ( a, b) as A

    what is the difference between updating it as B, using set, compared to just making it equal B:

    A = B;
    or 
    A.x = B.x;
    A.y = B.y;
    and
    A.set(B);
    A.set(B.x, B.y);
    

    Also no idea what the last two things are doing, esp. clone:

      @ Override public Vec2D clone() {
        try {
          return (Vec2D) super.clone();
        } 
        catch (final CloneNotSupportedException ex) {
          throw new RuntimeException(ex);
        }
      }
    
      @ Override public String toString() {
        return "[ " + x + ", " + y + " ]";
      }
    
  • The first set() function is calling the second set function, so it is the second set function the one that is doing all the work. Having multiple set functions to handle different situations is common (and quite useful) and having one of them to do the final operation ensures consistency across all the functions. Consistency is important when the functionality is literally the same.

    For the final part, it ensures the vector is not changed during this operation. It is more for practice (and a good habit) since setting should not modify the passed reference. I let @GoToLoop add any other comment...

    @GoToLoop: Wouldn't be possible to extend Vec2D from PVector and just provide a constructor that takes double arguments and internally create a PVector with the arguments casted to float? I am thinking more of to be able to reuse all the code implemented in the PVector class. Would that be a valid approach or I am overlooking something?


    For annotations:
    https://docs.oracle.com/javase/tutorial/java/annotations/predefined.html


    @nnenov
    https://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html

    @GoToLoop This guarantees you do a deep copy for this class without any other implementation?

    Kf

  • edited May 2017

    Wouldn't be possible to extend Vec2D from PVector ...

    In a hackish way yes! But it'd demand many changes. And still it'd be very buggy. :-&
    Here's some partial attempt. Not trustful at all though: :@)

    // forum.Processing.org/two/discussion/22209/
    // 2d-mandelbrot-sketch-adapted-to-use-doubles-
    // now-doesn-t-work#Item_5
    
    // 2017-Apr-27
    
    void setup() {
      println(new Vec2D(PVector.random3D(this)));
      println(new Vec2D().set(PVector.random3D(this)));
      exit();
    }
    
    static public class Vec2D extends PVector {
      double x, y;
    
      public Vec2D() {
      }
    
      public Vec2D(final double n) {
        set(n, n);
      }
    
      public Vec2D(final double x, final double y) {
        set(x, y);
      }
    
      public Vec2D(final PVector v) {
        set((double) v.x, v.y);
      }
    
      @ Override public Vec2D set(final PVector v) {
        return set((double) v.x, v.y);
      }
    
      public Vec2D set(final double px, final double py) {
        x = px;
        y = py;
        return this;
      }
    
      public PVector set(final double[] xy) {
        return xy != null && xy.length >= 2? set(xy[0], xy[1]) : this;
      }
    
      public Vec2D add(final double px, final double py) {
        return set(x + px, y * py);
      }
    
      public Vec2D sub(final double px, final double py) {
        return set(x - px, y - py);
      }
    
      public Vec2D mult(final double n) {
        return set(x * n, y * n);
      }
    
      public Vec2D div(final double n) {
        return set(x / n, y / n);
      }
    
      public double magSqD() {
        return x*x + y*y;
      }
    
      public double magD() {
        return Math.sqrt(magSqD());
      }
    
      public double distSqD(final PVector v) {
        final double dx = x - v.x, dy = y - v.y;
        return dx*dx + dy*dy;
      }
    
      public double distD(final PVector v) {
        return Math.sqrt(distSqD(v));
      }
    
      public double dotD(final PVector v) {
        return x*v.x + y*v.y;
      }
    
      public double dotD(final double px, final double py) {
        return x*px + y*py;
      }
    
      public double headingD() {
        return Math.atan2(y, x);
      }
    
      @ Override public Vec2D clone() {
        try {
          return (Vec2D) super.clone();
        } 
        catch (final CloneNotSupportedException ex) {
          throw new RuntimeException(ex);
        }
      }
    
      @ Override public String toString() {
        return "[ " + x + ", " + y + " ]";
      }
    }
    
  • edited April 2017

    I don't understand the concept of using final as a type ...

    Keyword final isn't a datatype in the same vein public isn't it either. It is a modifier. :-B
    When used on a variable, final makes it impossible to use operator = and its siblings on it after it's got its initial value: https://Processing.org/reference/final.html

  • edited April 2017

    What is the difference between updating it as B, using set, compared to just making it equal B.

    It's huge that difference! Assigning an object variable to another variable using the operator = makes them both alias for the very same object! :-SS

    Regardless the alias variable we use to mutate the object it points to, if we use the other alias, we'll realize the mutation was mirrored there too. @-)

    Also no idea what the last two things are doing, esp. clone().

    That's why I've implemented a clone() method for class Vec2D! ;;)
    So we can avoid the trap of having alias for the same object. $-)

    You see, when we invoke clone(), a new Vec2D object is created, but w/the same content as the original.

    We can safely mutate this cloned object w/o fearing of having the changes reflected on the original! \m/

    For example, if we call vecA.add(vecB);, vecA is mutated by the add() method's result.
    However, if we call clone() before add(): Vec2D vecC = vecA.clone().add(vecB);
    We get the result of the add() operation on the newly cloned object rather than directly in vecA.
    So now we've got a 3rd Vec2D object assigned to variable vecC w/ the result of vecA + vecB. :)>-

  • edited April 2017

    This guarantees you do a deep copy for this class without any other implementation?

    @kfrajer, clone() method creates a shallow copy:
    http://docs.Oracle.com/javase/8/docs/api/java/lang/Object.html#clone--

    However, since class Vec2D doesn't have any fields w/ a mutable object datatype, rather it's just 2 primitive fields x & y, a shallow copy is all we need here. :P

    Otherwise we'd need to clone() each mutable object as well! #:-S

  • @kfrajer , why does the second set function return "this"?? I can see how the first takes a vector and calls the next function of the same name with the vector components as separate fields, but what is the actual purpose / practical application for these functions? Is it so you can have the option to say foo.set(foo1) rather than foo = foo1?

    Is the second set function just returning itself/ the current object, a 2D double prec. vector object? if so, why do all the other functions not return "this"

    @GoToLoop , I don't understand why final is used in these functions' input fields. is it to help save memory/ speed things up? why do they need to be protected?

  • I don't understand why final is used in these functions' input fields.

    By "functions' input fields" I believe you mean functions' parameters, right? L-)
    Neither final nor public are necessary for this class. You can simply remove them! ;)

    Is it so you can have the option to say foo.set(foo1) rather than foo = foo1?

    Like I've said, if we assign an object variable to another object variable they both become alias for the same object. :-@

    Therefore, foo.set(foo1) isn't the same thing as foo = foo1!
    Rather foo.set(foo1) is equivalent of foo.x = foo1.x; fox.y = foo1.y;. :-B

  • edited April 2017

    Why does the second set() function return this??

    In order to allow method chaining like this: vecA.set(Math.PI, 1e3d).add(vecB).mul(-3.57d); $-)

    https://GitHub.com/processing/processing/blob/master/core/src/processing/core/PVector.java

  • @GoToLoop I'm sorry I didn't see your previous reply about mutation for some reason! I didn't know this was a thing, I think I heard about this happening in python..

    when you said "Regardless the alias variable we use to mutate the object it points to, if we use the other alias, we'll realise the mutation was mirrored there too."

    Would you mind sharing a practical example of this occurring in processing? I always "set" stuff just using = and haven't noticed this mirrored behaviour, but I am not exactly a seasoned coder.

  • edited April 2017

    Object alias example:

    PVector a = new PVector(10, 20);
    println(a); // [ 10.0, 20.0, 0.0 ]
    
    PVector b = a; // alias of a
    b.add(15, -15);
    println(a); // [ 25.0, 5.0, 0.0 ]
    
    exit();
    

    Object clone example:

    PVector a = new PVector(10, 20);
    println(a); // [ 10.0, 20.0, 0.0 ]
    
    PVector b = a.get(); // clone of a
    b.add(15, -15);
    println(a); // [ 10.0, 20.0, 0.0 ]
    
    exit();
    

    New Object followed by set() example:

    PVector a = new PVector(10, 20);
    println(a); // [ 10.0, 20.0, 0.0 ]
    
    PVector b = new PVector().set(a); // set() of a
    b.add(15, -15);
    println(a); // [ 10.0, 20.0, 0.0 ]
    
    exit();
    
  • Answer ✓

    Thank you, this really cleared it up for me. I need to go through, check and revise my code now to make sure I am conforming to this.

Sign In or Register to comment.