Ellipse size

Hi there, I have some strange behavior in my code.

  void display() { 
    noStroke();
    String note = freqAndNote.fromFreqToNote(frequency);
    freqAndColour.noteToColour(note);
    ellipse(loc.x, loc.y, 20, 20);
  }

freqAndColour.noteToColour(note) returns the colour of the ellipse: fill((noteIndex * (100/12)), 50, octave * (100/6));

However, the size of the ellipses change when I cycle through different types of visualizations in my sketch. If the width and height are specified in pixels and there is a noStroke() before drawing, the size should be consistent. Right?

Any ideas?

Tagged:

Answers

  • when there is no scale() somewhere.....

    it's hard to say without seeing more code though

  • My sketch is quite long at this point, I don't really think it would be appropriate to post all of it here. I will add below all the code related to these ellipses. I can tell you that I don't use scale() anywhere though.

    The ellipses are controlled using vector math, using the library toxiclibs, toxi.geom.*; Here is the code related to these ellipses:

    class Note {
    
      Vec3D loc = new Vec3D(0, 0, 0);
      Vec3D speed = new Vec3D(random(-2, 2), random(-2, 2), 0);
      Vec3D acc = new Vec3D();
      Vec3D grav = new Vec3D(0, 0.2, 0);
    
      //Note parameters
      int positionX = 0;
      int positionY = 0;
      float frequency = 0;
      float amplitude = 0;
      int timer = 0;
    
      //Constructor:
      Note(Vec3D _loc, float _frequency, float _amplitude, int _timer) {
        loc = _loc;
        frequency = _frequency;
        amplitude = _amplitude;
        timer = _timer;
      }
    
      void run() {
    
        display();
        move();
        bounce();
        //gravity();
        //lineBetween();
        flock();
        timer--;
      }
    
    
      void display() { // FIX THIS
        noStroke();
        String note = freqAndNote.fromFreqToNote(frequency);
        freqAndColour.noteToColour(note);
        ellipse(loc.x, loc.y, 20, 20);
      }
    
      void gravity() {
        speed.addSelf(grav);
      }  
    
      void bounce() {
        if (loc.x > width/2) {
          speed.x = speed.x * (-1);
        }
        if (loc.x < -width/2) {
          speed.x = speed.x * (-1);
        }
        if (loc.y > height/2) {
          speed.y = speed.y * (-1);
        }
        if (loc.y < -height/2) {
          speed.y = speed.y * (-1);
        }
      }
    
      void move() {
        speed.addSelf(acc);
        speed.limit(2);
        loc.addSelf(speed);
        //Because it updates with addSelf:
        acc.clear();
      }
    
      void lineBetween() {
        for (int i = 0; i < noteCollection.size (); i++) {
          Note other = (Note) noteCollection.get(i);
          float distance = loc.distanceTo(other.loc);
    
          if ((distance > 0) && (distance < 40)) {
            stroke(255, 0, 0);
            strokeWeight(0.4);
            line(loc.x, loc.y, other.loc.x, other.loc.y);
          }
        }
      }
    
      void flock() {
        //Notes bounce of each other.
        separate(5);
        //Notes try to find each other.
        cohesion(0.001);
        //Notes try to move in one direction as a group.
        align(0.1);
      }
    
      //Notes bounce of each other.
      void separate(float magnitude) {
        Vec3D steer = new Vec3D();
        int count = 0;
    
        for (int i = 0; i < noteCollection.size (); i++) {
          Note other = (Note) noteCollection.get(i);
    
          float distance = loc.distanceTo(other.loc);
    
          if ((distance > 0) && (distance < 30)) {
    
            Vec3D diff = loc.sub(other.loc);
            diff.normalizeTo(1.0/distance);
    
            steer.addSelf(diff);
            count++;
          }
        }
    
        if (count > 0) {
          steer.scaleSelf(1.0/count);
        }
        steer.scaleSelf(magnitude);
        acc.addSelf(steer);
      }  
    
      //Notes try to find each other.
      void cohesion(float magnitude) {
        Vec3D sum = new Vec3D();
        int count = 0;
    
        for (int i = 0; i < noteCollection.size (); i++) {
          Note other = (Note) noteCollection.get(i);
    
          //Notes try to find other notes with the same frequency.
          if (other.frequency == this.frequency) {
    
            float distance = loc.distanceTo(other.loc);
    
            if ((distance > 0) && (distance < 60)) {
              //Vector average of the positions of the other notes.
              sum.addSelf(other.loc);  
              count++;
            }
          }
        }
        if (count > 0) {
          sum.scaleSelf(1.0/count);
        }
        Vec3D steer = sum.sub(loc);
        steer.scaleSelf(magnitude);
        acc.addSelf(steer);
      }
    
      //Notes try to move in one direction as a group.
      void align(float magnitude) {
        Vec3D steer = new Vec3D();
        int count = 0;
    
        for (int i = 0; i < noteCollection.size (); i++) {
          Note other = (Note) noteCollection.get(i);
    
          //Notes try to find other notes with the same frequency.
          if (other.frequency == this.frequency) {
    
            float distance = loc.distanceTo(other.loc);
    
            if ((distance > 0) && (distance < 40)) {
              //Mimic the rest of the notes
              steer.addSelf(other.speed);
              count++;
            }
          }
        }
        if (count > 0) {
          steer.scaleSelf(1.0/count);
        }
        steer.scaleSelf(magnitude);
        acc.addSelf(steer);
      }  
    
      /*
      void behaviour() {
    
       }
       */
    }
    

    And inside of draw() we have:

     if ((runMode == 5)) {
        //bandFiltering();
    
        create(bands); 
    
        pushMatrix();
        translate(width/2, height/2);
        background(0); 
    
        //for (int i = 0; i < noteCollection.size (); i++) {
        //Had to change for loop because we can't use remove() for a List unless it's backwards  
        for (int i = noteCollection.size (); i-- !=0; ) {
    
          Note note = (Note) noteCollection.get(i);
          note.run();
    
          if (note.timer == 0) {
            //println("Note removed");
            noteCollection.remove(note);
          }
        }
        popMatrix();
      }
    

    And outside of draw to create the items of the list:

    void create(int totalBands) {
      pushMatrix();
      translate(width/2, height/2);
    
      for (int i = 0; i < totalBands; i++) {
        float[][] dominantFreq = filter.dominantFreq(filter.filter((limitFreq/totalBands) * (i), (limitFreq/totalBands) * (i+1), filter.fftArray));
        //println("Int i = " + i);
        //If amplitude is big enough:
        if (dominantFreq[1][0] > 0.5  ) {
    
          //Create a new  note
          int ellipseXMin = -width/2 + i * (width/totalBands);
          int ellipseXMax = -width/2 + (i+1) * (width/totalBands);
          int ellipseX = int(random(ellipseXMin, ellipseXMax));
          Vec3D origin = new Vec3D(ellipseX, 0, 0);
    
          //println("Note frequency " + dominantFreq[0][i] + " and note amplitude " +  dominantFreq[1][i]);
          //println("Note origin " + origin);
          //Note note = new Note(origin, dominantFreq[0][i], dominantFreq[1][i], 100);
          Note note = new Note(origin, dominantFreq[0][0], dominantFreq[1][0], 10000);
          noteCollection.add(note);
        }
      }  
    
      popMatrix();
    }
    
  • "My sketch is quite long at this point, I don't really think it would be appropriate to post all of it here."

    WHAT CAN WE DO TO CRUSH THIS SILLY NOTION?!?

    It's should be sort of inappropriate to NOT post all your code.

  • Hi, Well I'm sorry about that. I guess I'm still new here. I'm not at home right now to post all of my work. However, what I asked earlier: if the width and height are specified in pixels and there is a noStroke() before drawing, the size should be consistent. Right?

  • Actually, if your sketch is too big, it's indeed not feasible to post it fully in this forum.
    However, we do need to see both setup() & draw().
    And most importantly, we need to see where any fields used by the posted code were declared & initialized!

  • Here's more code:

    import ddf.minim.analysis.*;
    import ddf.minim.*;
    import controlP5.*;
    import toxi.geom.*;
    
    Minim minim;
    AudioInput in;
    FFT fft;
    BeatDetect beat;
    Filter filter;
    FreqAndNote freqAndNote;
    FreqAndColour freqAndColour;
    
    ControlP5 cp5;
    DropdownList dropDownList;
    
    ArrayList noteCollection = new ArrayList();
    
    int runMode = 0;
    int menu = 0;
    
    int bands = 20;
    int arrayRows = 2;
    
    int flagNoteFrequency = 0;
    int flagNoteCollection = 0;
    
    int bass = 300;
    int mids = 1000;
    int treble = 4000;
    
    float [][] bassArray;
    float [][] bassDominantFreq;
    float [][] midsArray;
    float [][] midsDominantFreq;
    float [][] trebleArray;
    float [][] trebleDominantFreq;
    
    float [][] dominantFreq = new float [arrayRows][bands];
    
    int limitFreq = 15000;  
    
    int backgroundMode = 0;
    String [] arrayNotes = { "Do C", "Do# Reb C# Bb", "Re D", "Re# Mib D# Eb", "Mi E", "Fa F", "Fa# Solb F# Gb", "Sol G", "Sol# Lab G# Ab", "La A", "La# Sib A# Bb", "Si B" };;
    
    int numColors = 12;
    int wheelDiameter = 600;
    float colorSpacing = 1;
    int wheelThickness = 120;
    
    
    void setup() {
    
      size(1920, 1080, P3D);
      //size(1280, 720, P3D);
      smooth();  
      background(0);
    
      minim = new Minim(this);
      in = minim.getLineIn(Minim.STEREO, 512);
      fft = new FFT(in.bufferSize(), in.sampleRate());
      //fft.logAverages(60, 7);
      fft.linAverages(80);
    
      filter = new Filter();
      freqAndNote = new FreqAndNote();
      freqAndColour = new FreqAndColour();
    
    
      cp5 = new ControlP5(this);
      // create a DropdownList
      dropDownList = cp5.addDropdownList("myList").setPosition(20, 40);
    
      customize(dropDownList); // customize the list
    
    }
    
    void draw() {  
    
      colorMode(RGB, 255);
    
    
      fft.forward(in.mix);
    
      filter.run(fft, runMode, bands);
    
    
      if ((runMode == 5)) {
    
        create(bands); 
    
        pushMatrix();
        translate(width/2, height/2);
        background(0); 
    
        //for (int i = 0; i < noteCollection.size (); i++) {
        //Had to change for loop because we can't use remove() for a List unless it's backwards  
        for (int i = noteCollection.size (); i-- !=0; ) {
    
          Note note = (Note) noteCollection.get(i);
          note.run();
    
          if (note.timer == 0) {
            //println("Note removed");
            noteCollection.remove(note);
          }
        }
        popMatrix();
      }
    
      if ((runMode == 7)) {
    
        colorMode(HSB, 360, 100, 100);
        background(0);
    
        strokeWeight(wheelThickness);
        noFill();
        strokeCap(SQUARE);
    
        int colorAngle = 360/numColors;
    
        pushMatrix();
        translate(width/2, height/2);
    
        //arrayNotes = { "Do C", "Do# Reb C# Bb", "Re D", "Re# Mib D# Eb", "Mi E", "Fa F", "Fa# Solb F# Gb", 
                       //"Sol G", "Sol# Lab G# Ab", "La A", "La# Sib A# Bb", "Si B" };
    
        for (int i = 0; i < numColors; i++) {
    
          float startAngle = i * colorAngle + colorSpacing;
          float stopAngle = (i + 1) * colorAngle - colorSpacing;
    
          //Colour
          stroke(startAngle, 80, 90);
          arc(0, 0, wheelDiameter, wheelDiameter, radians(startAngle), radians(stopAngle));
    
        }
        for (int i = 0; i < numColors; i++) {
          textSize(28);
    
          text(arrayNotes[i], (wheelDiameter/2 + wheelThickness/2) * cos(i*PI/6 + PI/12), (wheelDiameter/2 + wheelThickness/2)* sin(i*PI/6 + PI/12));
        }  
    
        popMatrix();
    
      }  
    
    }
    
    void create(int totalBands) {
      pushMatrix();
      translate(width/2, height/2);
    
      for (int i = 0; i < totalBands; i++) {
        float[][] dominantFreq = filter.dominantFreq(filter.filter((limitFreq/totalBands) * (i), (limitFreq/totalBands) * (i+1), filter.fftArray));
        //println("Int i = " + i);
        //If amplitude is big enough:
        if (dominantFreq[1][0] > 0.5  ) {
    
          //Create a new  note
          int ellipseXMin = -width/2 + i * (width/totalBands);
          int ellipseXMax = -width/2 + (i+1) * (width/totalBands);
          int ellipseX = int(random(ellipseXMin, ellipseXMax));
          Vec3D origin = new Vec3D(ellipseX, 0, 0);
    
          //println("Note frequency " + dominantFreq[0][i] + " and note amplitude " +  dominantFreq[1][i]);
          //println("Note origin " + origin);
    
          Note note = new Note(origin, dominantFreq[0][0], dominantFreq[1][0], 10000);
          noteCollection.add(note);
        }
      }  
    
      popMatrix();
    }
    

    Some auxiliary classes:

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    class FreqAndColour {
    
      //Parameters
      String NOTE_SYMBOL[] = {
        "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", 
        "A#", "B"
      };
    
      //Constructor
      FreqAndColour() {
      }
    
      void noteToColour (String string) {
    
        Pattern p = Pattern.compile("([a-zA-Z]{1}[#]?)([\\d]?)");
        Matcher m = p.matcher(string);
        if (m.find()) {
          //Note
          String note = m.group(1);
          //println(note);
          //Octave
          int octave = int(m.group(2));
          //println(octave);
    
          int noteIndex = 0;
    
          for (int i = 0; i < NOTE_SYMBOL.length; i++) {
            if ( note.equals(NOTE_SYMBOL[i]) ) {
              noteIndex = i;
            }
          }
    
          colorMode(HSB, 100); 
          fill((noteIndex * (100/12)), 50, octave * (100/6));
        }
      }
    }
    
    class FreqAndNote {
    
      double PITCH_OF_A4 = 57D;
      double FACTOR = 12D / Math.log(2D);
      String NOTE_SYMBOL[] = {
        "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", 
        "A#", "B"
      };
    
      float frequencyOfA4 = 440F;
      float frequency;
    
      //Constructor:
      FreqAndNote() {
      }
    
    
      double getPitch (double d) {
        return 57D + FACTOR * Math.log(d / (double)frequencyOfA4);
      }
    
      float getFrequency(double d) {
        return (float)(Math.exp((d - 57D) / FACTOR) * (double)frequencyOfA4);
      }
    
      String makeNoteSymbol(double d) {
        int i = (int)(d + 120.5D);
        StringBuffer stringbuffer = new StringBuffer(NOTE_SYMBOL[i % 12]);
        stringbuffer.append(Integer.toString(i / 12 - 10));
        return new String(stringbuffer);
      }
    
      float valueOf(String s) {
        return (new Float(s)).floatValue();
      }
    
      int parseNoteSymbol(String s) {
        s = s.trim().toUpperCase();
        for (int i = NOTE_SYMBOL.length - 1; i >= 0; i--)
        {
          if (!s.startsWith(NOTE_SYMBOL[i])) {
            continue;
          }
          return i + 12 * Integer.parseInt(s.substring(NOTE_SYMBOL[i].length()).trim());
        }
        return 0;
      }
    
      String fromFreqToNote(float frequency) {
        return makeNoteSymbol(getPitch(frequency));
      }
    
      float fromNoteToFreq (String string) {
        //return getFrequency(parseNoteSymbol(string));
        float f = parseNoteSymbol(string);
    
        println(f);
        return getFrequency(f);
      }
    }
    

    I would really appreciated if someone would answer my question: if the width and height are specified in pixels and there is a noStroke() before drawing, the size should be consistent. Right?

  • Anything? :\

  • noStroke() just means to not draw an outline around your ellipses.

    Also, no. Ellipses with the same width and height can appear different sizes, based on the scale of the coordinate system used to draw then. Example:

    size(440,440);
    background(0);
    ellipse(20,20,30,30);
    scale(4);
    ellipse(20,20,30,30);
    scale(4);
    ellipse(20,20,30,30);
    
  • I don't use the function scale() in my code though :\

  • But your sketch is 3D, right?

    void setup(){
      size(400,400,P3D);
    }
    
    void draw(){
      background(0);
      translate(width/2,height/2);
    
      pushMatrix();
      translate(-100,-100,-100);
      ellipse(0,0,30,30);
      popMatrix();
    
      ellipse(0,0,30,30);
    
      pushMatrix();
      translate(100,100,100);
      ellipse(0,0,30,30);
      popMatrix();
    
    }
    
  • Right, I use a 3D engine, but I don't use the Z coordinate, everything should be on the same plane. I thought it was necessary to use P3D for the vector math I'm doing. The only thing I can think of is I use push and popMatrix to do translate(width/2,height/2);

  • Could you run your sketch and take an image of it? I can't run it, so trying to picture where the ellipses of different sizes are is sort of hard. Or post a simplified example? Or are your ellipses the same size? If so, no problem...

  • edited July 2015

    Hi! I uploaded a short video with whats happening, about 15 secs long. So I start with the mode I'm trying to fix, then I switch to something else, and when I go back the size has changed. https://vid.me/7Bwt

    Ignore the music, as I need something to be playing because the sketch samples the audio and produces the ellipses from the samples.

    You'd think that something from the other modes was interfering, but the ellipses are drawn specifying pixels, the only thing I can think of is the translate, but that shouldn't change the size, just where they appear! I can't think of anything that makes sense.

  • I don't see where your code is drawing any ellipses... Can you point out /repost the part that does the actual drawing?

  • Hi there! In the class Note there is:

    void display() { // FIX THIS
        noStroke();
        String note = freqAndNote.fromFreqToNote(frequency);
        freqAndColour.noteToColour(note);
        ellipse(loc.x, loc.y, 20, 20);
      }
    
  • then I switch to something else

    Ok, what is it?

  • Can you also try to go to 2D instead of 3D in setup() and in size()

    Chrisir

Sign In or Register to comment.