diff --git a/B12NumbersV3/B12Char.pde b/B12NumbersV3/B12Char.pde new file mode 100644 index 0000000..cb3b50f --- /dev/null +++ b/B12NumbersV3/B12Char.pde @@ -0,0 +1,34 @@ +class B12Char extends B12Digit{ + char c; + + B12Char(char _c){ + super(0); + if(_c == '-' || _c == '.' || _c == ':'){ + c = _c; + }else{ + throw new IllegalArgumentException("B12Char only accepts \'-\', \'.\', and ':'"); + } + } + + @Override + void display(){ + pushMatrix(); + translate(refPos.x,refPos.y); + strokeWeight(1); + + switch(c) { + case '-': + lineMinus(); break; + case '.': + strokeWeight(2); period(); break; + case ':': + strokeWeight(2); colon(); break; + } + + popMatrix(); + } + + void lineMinus(){ line(3,-5,9,-5); } + void period(){ point(5,0); } + void colon(){ point(5,-2); point(5,-8); } +} diff --git a/B12NumbersV3/B12Digit.pde b/B12NumbersV3/B12Digit.pde new file mode 100644 index 0000000..629a602 --- /dev/null +++ b/B12NumbersV3/B12Digit.pde @@ -0,0 +1,66 @@ +//package java.base.lang; +class B12Digit{ + byte value; + PVector refPos; + + B12Digit(int _value){ + if(_value >= 12 || _value < 0){ + throw new IllegalArgumentException("B12Digit only accepts decimal integers 0 through 11"); + } + value = byte(_value); + refPos = new PVector(0,0); + } + + // SETTERS + void setRefPos(PVector _refPos){ refPos = _refPos; } + void setRefPos(float _x, float _y){ refPos = new PVector(_x,_y); } + void setValue(int _value){ value = byte(_value); } + + // GETTERS + PVector getRefPos(){ return refPos; } + int getValue(){ return value; } + + // RENDER CHARACTERS + void display(){ + pushMatrix(); + translate(refPos.x,refPos.y); + strokeWeight(1); + noFill(); + ellipseMode(CORNERS); + switch(value) { + case 0: + line0(); break; + case 1: + line1(); break; + case 2: + line1(); line2(); break; + case 3: + line1(); line2(); line3(); break; + case 4: + line4(); break; + case 5: + line4(); line1(); break; + case 6: + line4(); line1(); line2(); break; + case 7: + line4(); line1(); line2(); line3(); break; + case 8: + line8(); line4(); break; + case 9: + line8(); line4(); line1(); break; + case 10: + line8(); line4(); line1(); line2(); break; + case 11: + line8(); line4(); line1(); line2(); line3(); break; + } + popMatrix(); + } + + // Individual shape components to build any B12 number + void line0(){ ellipse(0,-13,8,0); } + void line1(){ line(6,0,9,-10); } + void line2(){ line(3,-10,6,0); } + void line3(){ line(0,0,3,-10); } + void line4(){ line(9,-10,2,-13); } + void line8(){ line(2,-13,9,-16); } +} diff --git a/B12NumbersV3/B12Float.pde b/B12NumbersV3/B12Float.pde new file mode 100644 index 0000000..a208fc0 --- /dev/null +++ b/B12NumbersV3/B12Float.pde @@ -0,0 +1,133 @@ +class B12Float { + private ArrayList digits; + private float value; + private PVector pos; + private boolean arrayLoaded; + private boolean inPosition; + private int mode;// Can be RIGHT (39), CENTER (3), or LEFT (37) + private int places; + private int pointPlace; + + B12Float(float _value){ + value = _value; + pos = new PVector(0,0); + arrayLoaded = false; + inPosition = false; + mode = DECIMAL; + places = 4; + } + + float getValue(){ return value; } + void setValue(float _value){ value = _value; arrayLoaded = false; } + + PVector getPos(){ return pos; } + void setPos(PVector _pos){ pos = _pos.copy(); inPosition = false; } + void setPos(float _x, float _y){ pos = new PVector(_x, _y); inPosition = false; } + + int getPlaces(){ return places; } + void setPlaces(int _places){ + if(_places > 12 || _places < 0){ + throw new IllegalArgumentException("B12Float ncan only display to 12 duodecimal points"); + }else{ + places = _places; + } + } + + void setAlignMode(int _mode){ + if(_mode == DECIMAL || _mode == LEFT || _mode == RIGHT){ mode = _mode; } + else{ println("Alignment only accepts LEFT, RIGHT, and DECIMAL"); } + } + + void display(){ + if(!arrayLoaded){ loadArray(); } + if(!inPosition){ positionDigits(); } + pushMatrix(); + translate(pos.x,pos.y); + for(int i = 0; i < digits.size(); i++){ + digits.get(i).display(); + } + popMatrix(); + } + + private void positionDigits(){ + int curPos = 0; + int count = 0; + if(mode == LEFT){ + for(int i = 0; i < pointPlace; i++){ + curPos += -12; + digits.get(i).setRefPos(curPos, 0); + count++; + } + + curPos += -8; + digits.get(count).setRefPos(curPos, 0); + count++; + curPos += -6; + digits.get(count).setRefPos(curPos, 0); + count++; + + for(int i = count; i < digits.size(); i++){ + curPos += -12; + digits.get(i).setRefPos(curPos, 0); + } + }else if(mode == DECIMAL){ + curPos = -5; + digits.get(pointPlace).setRefPos(curPos,0); + curPos += -2; + for(int i = pointPlace - 1; i >= 0; i--){ + curPos += 12; + digits.get(i).setRefPos(curPos,0); + } + curPos = -2; + + for(int i = pointPlace + 1; i < digits.size(); i++){ + curPos += -12; + digits.get(i).setRefPos(curPos,0); + } + }else if(mode == RIGHT){ + for(int i = digits.size() - 1; i >= 0; i--){ + digits.get(count).setRefPos((12 * i) + 3, 0); + count++; + } + } + inPosition = true; + } + + private void loadArray(){ + digits = new ArrayList(); + B12Digit[] temp = new B12Digit[places]; + float mval = abs(value); + int whole = int(mval); + float deci = mval - float(whole); + + for(int i = 0; i < places; i++){ + deci *= 12; + temp[i] = new B12Digit(int(deci)); + deci -= float(int(deci)); + } + + for(int i = places - 1; i >= 0; i--){ + digits.add(temp[i]); + } + + pointPlace = digits.size(); + digits.add(new B12Char('.')); + + while(whole > 0){ + if(whole < 12){ + digits.add(new B12Digit(whole)); + whole = 0; + }else{ + digits.add(new B12Digit(whole % 12)); + whole /= 12; + } + } + + if(value < 0){ + digits.add(new B12Char('-')); + } + + arrayLoaded = true; + inPosition = false; + } +} diff --git a/B12NumbersV3/B12Int.pde b/B12NumbersV3/B12Int.pde new file mode 100644 index 0000000..eaed62a --- /dev/null +++ b/B12NumbersV3/B12Int.pde @@ -0,0 +1,81 @@ +class B12Int { + private ArrayList digits; + private int value; + private PVector pos; + private boolean arrayLoaded; + private boolean inPosition; + private int mode;// Can be RIGHT (39), CENTER (3), or LEFT (37) + private int minLen; + + B12Int(int _value){ + value = _value; + pos = new PVector(0,0); + arrayLoaded = false; + inPosition = false; + mode = LEFT; + minLen = 0; + } + + int getValue(){ return value; } + void setValue(int _value){ value = _value; arrayLoaded = false; } + + void setPos(PVector _pos){ pos = _pos.copy(); inPosition = false; } + void setPos(float _x, float _y){ pos = new PVector(_x, _y); inPosition = false; } + PVector getPos(){ return pos; } + + void setMinLen(int i){ minLen = i; } + + void setAlignMode(int _mode){ + if(_mode == DECIMAL || _mode == LEFT || _mode == RIGHT){ mode = _mode; } + else{ println("Alignment only accepts LEFT, RIGHT, and DECIMAL"); } + } + + void display(){ + if(!arrayLoaded){ loadArray(); } + if(!inPosition){ positionDigits(); } + pushMatrix(); + translate(pos.x,pos.y); + for(int i = 0; i < digits.size(); i++){ + digits.get(i).display(); + } + popMatrix(); + } + + private void positionDigits(){ + if(mode == LEFT || mode == DECIMAL){ + for(int i = 0; i < digits.size(); i++){ + digits.get(i).setRefPos((-12 * (i+1)), 0); + } + }else if(mode == RIGHT){ + int count = 0; + for(int i = digits.size() - 1; i >= 0; i--){ + digits.get(count).setRefPos((12 * i) + 3, 0); + count++; + } + } + inPosition = true; + } + + private void loadArray(){ + digits = new ArrayList(); + int mval = abs(value); + if(mval == 0){ digits.add(new B12Digit(0)); } + while(mval != 0){ + if(mval < 12){ + digits.add(new B12Digit(mval)); + mval = 0; + }else{ + digits.add(new B12Digit(mval % 12)); + mval /= 12; + } + } + if(digits.size() < minLen){ + digits.add(new B12Digit(0)); + } + if(value < 0){ + digits.add(new B12Char('-')); + } + + arrayLoaded = true; + } +} diff --git a/B12NumbersV3/B12NumbersV3.pde b/B12NumbersV3/B12NumbersV3.pde new file mode 100644 index 0000000..12f56a3 --- /dev/null +++ b/B12NumbersV3/B12NumbersV3.pde @@ -0,0 +1,33 @@ +/* + B12NumbersV3 + Beta version of a clock in base 12. + by Nayan Sawyer + started Mar 2022 + version 0.1.2 April 4 2022 + + Characters are a variation of Kaktovik Inupiaq numerals + reversed and in base 12 instead of 20. I take no credit + for the design. +*/ + +public static int DECIMAL = 65; + +Clock clock; + +void setup(){ + size(400,400); + clock = new Clock(new STime48()); + println("waiting"); +} + +void draw(){ + background(196); + translate(width/2,height/2); + scale(1); + point(0,0); + clock.display(); +} + +void mouseClicked(){ + clock.setTime(new Time48(16,0,0)); +} diff --git a/B12NumbersV3/Clock.pde b/B12NumbersV3/Clock.pde new file mode 100644 index 0000000..ed2f74e --- /dev/null +++ b/B12NumbersV3/Clock.pde @@ -0,0 +1,73 @@ +class Clock { + PVector pos; + STime48 t48; + B12Int hours; + B12Int minutes; + B12Int seconds; + B12Char sep; + B12Int fill; + int tmillis; + //boolean initialized; + + Clock(STime48 _t48) { // TODO refactor time class + pos = new PVector(0, 0); + t48 = _t48; + hours = new B12Int(t48.hours()); + minutes = new B12Int(t48.mins()); + seconds = new B12Int(t48.secs()); + sep = new B12Char(':'); + fill = new B12Int(0); + + hours.setMinLen(2); + minutes.setMinLen(2); + seconds.setMinLen(2); + } + + PVector getPos() { + return pos; + } + void setPos(PVector _pos) { + pos = _pos.copy(); + } + void setPos(float _x, float _y) { + pos = new PVector(_x, _y); + } + + void setTime(Time48 _time) { + t48.setTime(_time); + //initialized = true; + } + + //public void syncTime(){ initialized = false; } // Allows syncing after time starts running + + void display() { + if (t48.synced()) { + // Time + hours.setValue(t48.hours()); + minutes.setValue(t48.mins()); + seconds.setValue(t48.secs()); + + // Position + hours.setPos(-64, 0); + minutes.setPos(-32, 0); + seconds.setPos(0, 0); + B12Char c1 = new B12Char(':'); + B12Char c2 = new B12Char(':'); + c1.setRefPos(-34, 0); + c2.setRefPos(-66, 0); + + // Display + pushMatrix(); + translate(pos.x, pos.y); + hours.display(); + c2.display(); + minutes.display(); + c1.display(); + seconds.display(); + popMatrix(); + //print(seconds.getValue()); + } else { + text("fetching current time", pos.x, pos.y); + } + } +} diff --git a/B12NumbersV3/STime48.pde b/B12NumbersV3/STime48.pde new file mode 100644 index 0000000..3675f83 --- /dev/null +++ b/B12NumbersV3/STime48.pde @@ -0,0 +1,43 @@ +class STime48 extends Time48{ + int offset; + int tmillis; + private boolean synced; + + STime48(){ + super(); + offset = 0; + tmillis = 0; + synced = false; + this.start(); + } + + boolean synced(){return synced;} + public void syncTime(){ synced = false; } // Allows syncing after time starts running + void setTime(Time48 _time){ + offset = _time.b10millis() - millis() - tmillis; + } + + @Override + public void run(){ + while(true){ + if(!synced){sync();} + + delay(1); // MUST USE DELAY OR OFFSET DOES NOT GET CALCULATED + if(tmillis + millis() + offset > 86400000){ tmillis -= 86400000; } // Fall over at 00:00 + setTsec(int((tmillis + millis() + offset) / 1562.5)); + } + } + + private void sync(){ + int sec = second(); + tmillis = 0; + while(true){ + if(sec != second()){ + tmillis = second()*1000 + minute()*60*1000 + hour()*60*60*1000; + synced = true; + println("synced"); + break; + } + } + } +} diff --git a/B12NumbersV3/Time.pde b/B12NumbersV3/Time.pde new file mode 100644 index 0000000..1caeac9 --- /dev/null +++ b/B12NumbersV3/Time.pde @@ -0,0 +1,96 @@ +/*class Time extends Thread{ + PVector pos; + B12Int hours; + B12Int minutes; + B12Int seconds; + B12Char sep; + B12Int fill; + int tmillis; + boolean initialized; + + Time(Time48 t48){ // TODO refactor time class + pos = new PVector(0,0); + hours = new B12Int(0); + minutes = new B12Int(0); + seconds = new B12Int(0); + sep = new B12Char(':'); + fill = new B12Int(0); + + hours.setMinLen(2); + minutes.setMinLen(2); + seconds.setMinLen(2); + + initialized = false; + this.start(); + //thread("this.runTime"); + } + + PVector getPos(){ return pos; } + void setPos(PVector _pos){ pos = _pos.copy(); } + void setPos(float _x, float _y){ pos = new PVector(_x,_y); } + + void setTime(int _h, int _m, int _s, boolean twelve){ + if(twelve){ + tmillis = int(((_h*48*48 + _m*48 + _s)*1562.5) - millis()); + }else{ + tmillis = (_h*60*60*1000 + _m*60*1000 + _s*1000) - millis(); + } + initialized = true; + } + + public void run(){ + while(true){ + if(!initialized){ sync(); } + if(tmillis + millis() > 86400000){ tmillis -= 86400000; } // Fall over at 00:00 + int sec48 = int((tmillis + millis()) / 1562.5); + int min48 = sec48 / 48; + int hour48 = min48 / 48; + sec48 -= min48 * 48; + min48 -= hour48 * 48; + //println(hour48 + ":" + min48 + ":" + sec48); + hours.setValue(hour48); + minutes.setValue(min48); + seconds.setValue(sec48); + } + } + + public void syncTime(){ initialized = false; } // Allows syncing after time starts running + private void sync(){ + int sec = second(); + tmillis = 0; + while(true){ + if(sec != second()){ + tmillis = second()*1000 + minute()*60*1000 + hour()*60*60*1000; + initialized = true; + break; + } + } + } + + void display(){ + if(initialized){ + // Position + + hours.setPos(-64, 0); + minutes.setPos(-32, 0); + seconds.setPos(0,0); + B12Char c1 = new B12Char(':'); + B12Char c2 = new B12Char(':'); + c1.setRefPos(-34,0); + c2.setRefPos(-66,0); + + // Display + pushMatrix(); + translate(pos.x,pos.y); + hours.display(); + c2.display(); + minutes.display(); + c1.display(); + seconds.display(); + popMatrix(); + //print(seconds.getValue()); + }else{ + text("initializing " + second(),pos.x,pos.y); + } + } +}*/ diff --git a/B12NumbersV3/Time48.pde b/B12NumbersV3/Time48.pde new file mode 100644 index 0000000..64e57d2 --- /dev/null +++ b/B12NumbersV3/Time48.pde @@ -0,0 +1,92 @@ +class Time48 extends Thread{ + private int sec48; + private int min48; + private int hour48; + private int tsec48; + private boolean initialized; + + // CONSTRUCTORS // + Time48(){ + sec48 = 0; + min48 = 0; + hour48 = 0; + tsec48 = 0; + initialized = false; + } + Time48(int _tsec48){ + tsec48 = _tsec48; + flattenTSec(); + initialized = true; + } + + Time48(Time48 t48){ + tsec48 = t48.tsec(); + flattenTSec(); + initialized = true; + } + Time48(int h, int m, int s){ + if(h >= 0 && h < 24){ hour48 = h;}else{throw new IllegalArgumentException();} + if(m >= 0 && m < 48){ min48 = m;}else{throw new IllegalArgumentException();} + if(s >= 0 && s < 48){ sec48 = s;}else{throw new IllegalArgumentException();} + flattenOther(); + initialized = true; + } + + // GETTERS // + int hours(){return hour48;} + int mins(){return min48;} + int secs(){return sec48;} + int tsec(){return tsec48;} + int[] t48(){int[] out = {hour48,min48,sec48}; return out;} + boolean initialized(){return initialized;} + int b10millis(){return int(float(tsec48) * 1562.5);} + + Time48 offset(Time48 t){ + return new Time48(t.tsec() + tsec48); + } + + Time48 copy(){ return new Time48(this); } + + // SETTERS // + void setHour(int h){ + if(h < 0 || h >= 24) throw new IllegalArgumentException(); + hour48 = h; + flattenOther(); + initialized = true; + } + void setMin(int m){ + if(m < 0 || m >= 48) throw new IllegalArgumentException(); + min48 = m; + flattenOther(); + initialized = true; + } + void setSec(int s){ + if(s < 0 || s >= 48) throw new IllegalArgumentException(); + sec48 = s; + flattenOther(); + initialized = true; + } + void setTsec(int s){ + tsec48 = s; + flattenTSec(); + initialized = true; + } + + // PRIVATE FUNCTIONS // + private void flattenTSec(){ + sec48 = tsec48; + min48 = sec48 / 48; + hour48 = min48 / 48; + + sec48 -= min48 * 48; + min48 -= hour48 * 48; + //println(t48()); + } + private void flattenOther(){ + tsec48 = hour48*48*48 + min48*48 + sec48; + } + + + // PLACEHOLDER FUNCTIONS // + public void run(){} +}