/* Copyright 2011 Toby D. Rule
This file is part of CompPad, an OpenOffice extension to provide live
mathematical and engineering calculations within a Writer document.
CompPad is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CompPad is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CompPad. If not, see <http://www.gnu.org/licenses/>.
*/
package com.CompPad.model;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.measure.unit.AlternateUnit;
import javax.measure.unit.ProductUnit;
import javax.measure.unit.Unit;
import org.jscience.physics.amount.Amount;
/**
*
* @author trule
*/
public class Utility {
public static Double zerotol=1E-13;
public static Integer numSigFigs = 4;
public static Integer numDecimalPlaces=2;
public static final int DECIMAL_SIGFIGS = 0;
public static final int DECIMAL_PLACES = 1;
public static final int DECIMAL_ENGINEERING = 2;
public static final int DECIMAL_SCIENTIFIC = 3;
public static Integer decimalFormat = DECIMAL_SIGFIGS;
public static char decimalSeparator = '.';
public static char thousandsSeparator = ' ';
public static void main(String [] args){
// test some methods
int i = 3;
System.out.println(scientificNotation(1.2345,i));
System.out.println(scientificNotation(1.2345,0));
System.out.println(scientificNotation(-1234.5,i));
System.out.println(scientificNotation(12.345,i));
System.out.println(scientificNotation(123.45,i));
System.out.println(scientificNotation(1234.5,i));
System.out.println(scientificNotation(1234567890.0,i));
}
public static void setDefaults(){
decimalSeparator = '.';
numSigFigs= 4;
numDecimalPlaces=2;
decimalFormat=DECIMAL_SIGFIGS;
}
private static String decimalPlaces(Double x,int i){
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
dfs.setDecimalSeparator(Utility.decimalSeparator);
dfs.setGroupingSeparator(Utility.thousandsSeparator);
String ixx = "";
if (i > 0){
ixx+= ".";
for (int j = 0; j < i; ++j ) {
ixx += "0";
}
}
DecimalFormat df = new DecimalFormat("#,##0"+ixx, dfs);
String formatString;
formatString=df.format(x);
// formatString=String.format("%"+"."+(i-1)+"f"+"\u00D7"+"10%s",base,UnicodeExp(ex));
return formatString;
}
private static String engineeringNotation(Double x, int i){
// exponential notation where the exponent is evenly divisible by 3,
// with i decimal places.
// Compute the exponent - lowest
int ex = (int)Math.floor(Math.log10(Math.abs(x)) / 3.0) * 3;
/* Rounded the number to the desired number of decimal places */
Double xx = Math.round(x*Math.pow(10.,i-ex))
/ Math.pow(10.,i-ex);
Double base = xx / Math.pow(10,ex);
System.out.println("base "+base + " exponent "+ex);
/* Formatter for alternate decimal separator */
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
dfs.setDecimalSeparator(Utility.decimalSeparator);
String ixx = "";
for (int j = 0; j < i; ++j ) {
ixx += "0";
}
/* Use exponential notation */
DecimalFormat df;
if (i==0){
df = new DecimalFormat("#,##0"+ixx, dfs);
}
else{
df = new DecimalFormat("#,##0."+ixx, dfs);
}
String formatString;
formatString=df.format(base)+String.format("\u00D7"+"10%s",UnicodeExp(ex));
return formatString;
}
private static String scientificNotation(Double x, int i){
// Exactly the same as engineeringNotation except for ex definition
// Compute the exponent - lowest
int ex = (int)Math.floor(Math.log10(Math.abs(x)));
/* Rounded the number to the desired number of decimal places */
Double xx = Math.round(x*Math.pow(10.,i-ex))
/ Math.pow(10.,i-ex);
Double base = xx / Math.pow(10,ex);
System.out.println("base "+base + " exponent "+ex);
/* Formatter for alternate decimal separator */
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
dfs.setDecimalSeparator(Utility.decimalSeparator);
String ixx = "";
for (int j = 0; j < i; ++j ) {
ixx += "0";
}
/* Use exponential notation */
DecimalFormat df;
if (i==0){
df = new DecimalFormat("#,##0"+ixx, dfs);
}
else{
df = new DecimalFormat("#,##0."+ixx, dfs);
}
String formatString;
formatString=df.format(base)+String.format("\u00D7"+"10%s",UnicodeExp(ex));
// formatString=String.format("%"+"."+(i-1)+"f"+"\u00D7"+"10%s",base,UnicodeExp(ex));
return formatString;
}
private static String sigFigs(Double x,int i){
/* Exponent */
int ex = (int)Math.round(Math.floor(Math.log10(Math.abs(x))));
/* Rounded */
Double xx = Math.round(x*Math.pow(10.,i-1-ex))
* Math.pow(10.,ex+1-i);
/* -10 < base < 10 */
Double base=xx/Math.pow(10,ex);
/* Number of places after decimal */
int ndecimal=(int)Math.round(i - 1 - Math.floor(Math.log10(Math.abs(x))));
//Logger.getLogger("com.CompPad").log(Level.FINE," base = "+base+" xx = "+xx+" ex = "+ex);
/* Formatter for alternate decimal separator */
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
dfs.setDecimalSeparator(Utility.decimalSeparator);
dfs.setGroupingSeparator(Utility.thousandsSeparator);
String ixx = "";
for (int j = 0; j < i - 1; ++j ) {
ixx += "0";
}
String ndecimalxx = "";
for (int j=0; j<ndecimal; ++j){
ndecimalxx += "0";
}
if (ndecimal<0 || ndecimal > 3+Utility.numSigFigs){
/* Use exponential notation */
DecimalFormat df;
if (i==1){
df = new DecimalFormat("#,##0"+ixx, dfs);
}
else{
df = new DecimalFormat("#,##0."+ixx, dfs);
}
String formatString;
formatString=df.format(base)+String.format("\u00D7"+"10%s",UnicodeExp(ex));
// formatString=String.format("%"+"."+(i-1)+"f"+"\u00D7"+"10%s",base,UnicodeExp(ex));
return formatString;
}
else if (ndecimal == 0){
/* No digits after decimal - omit separator */
DecimalFormat df = new DecimalFormat("#,##0", dfs);
return df.format(xx);
}
else{
DecimalFormat df = new DecimalFormat("#,##0."+ndecimalxx, dfs);
return df.format(xx);
// return String.format("%"+"."+ndecimal+"f",xx);
}
/* Now I need to convert to expondent if necessary */
/* Get rid of rounding error */
}
/* Convert i to Unicode exponent */
private static String UnicodeExp(int i){
/* Return a string expression to represent exponent using unicode
* superscripts */
String expString="";
String superscript[]={"\u2070","\u00B9","\u00B2","\u00B3","\u2074",
"\u2075","\u2076","\u2077","\u2078","\u2079"};
String minus = "\u207B";
if (Integer.signum(i)==-1){
expString=expString+minus;
}
String istring=Integer.toString(Math.abs(i));
int n=istring.length();
for (int j = 0; j<n; j++){
expString = expString + superscript[
Integer.valueOf(istring.substring(j, j+1))];
}
return expString;
}
private static String formatDouble(Double x){
String retval = null;
// Surround expressions with quotes so that the exponents display correctly
switch(decimalFormat){
case DECIMAL_SIGFIGS:
retval = "\""+sigFigs(x,numSigFigs)+"\"";
break;
case DECIMAL_PLACES:
retval = "\""+decimalPlaces(x,numDecimalPlaces)+"\"";
break;
case DECIMAL_ENGINEERING:
retval = "\""+engineeringNotation(x,numDecimalPlaces)+"\"";
break;
case DECIMAL_SCIENTIFIC:
retval = "\""+scientificNotation(x,numDecimalPlaces)+"\"";
break;
}
return retval;
}
private static String complexString(Double argReal, Double argImag){
String rstring;
String istring;
double mag = Math.sqrt(Math.pow(argReal,2.)
+ Math.pow(argImag,2));
if(Math.abs(argReal)>=zerotol*mag ){
rstring= formatDouble(argReal);
}
else{
rstring = "";
}
if ((Math.abs(argImag)<zerotol) & (Math.abs(argReal)<zerotol)){
rstring="0";
istring="";
}
else if (Math.abs(argImag)>=zerotol*mag){
/* Zero imaginary component */
if (!rstring.equals("")){
rstring=rstring+" + ";
}
istring = Utility.formatDouble(argImag)+ " i";
}
else{
istring = "";
}
return rstring + istring;
}
/* Compare a list of strings to a list of regexp */
public static List<Boolean> matchTokenList(List<String> list, List<String> regexp){
/* lists must be same size */
if (list.size() < regexp.size()){
return null;
}
else{
System.err.println(regexp);
List<Boolean> retval = new LinkedList();
Iterator<String> it = list.iterator();
for (String r : regexp){
String s = it.next();
System.out.print(r+" "+s);
retval.add(s.matches(r));
}
return retval;
}
}
/* This method splits up units that are a product of other units into their
* base units. */
/* This method should return units either in SI, NonSI, or combinations of
* units acording to the Unit.valueOf format. */
private static javax.measure.unit.Unit splitUnits(javax.measure.unit.Unit u){
Unit retval=Unit.ONE;
u=u.getStandardUnit();
/* If it's a ProductUnit, then split it and then call splitUnits */
if (javax.measure.unit.ProductUnit.class.isInstance(u)){
ProductUnit pu=(ProductUnit)u;
for (int i=0;i<pu.getUnitCount();++i){
/* First check to see if this unit needs split */
Unit ux =splitUnits(pu.getUnit(i));
retval=retval.times(ux.pow(pu.getUnitPow(i)));
}
/* Now split again */
Logger.getLogger("com.CompPad").log(Level.FINE,"ProductUnit "
+ pu.getUnitCount());
}
else if (javax.measure.unit.AlternateUnit.class.isInstance(u)){
retval=((AlternateUnit)u).getParent();
/* Now split again */
Logger.getLogger("com.CompPad").log(Level.FINE,
"AlternateUnit "+retval );
retval=splitUnits(retval);
}
else{
retval=u;
/* Must be base units */
}
return retval;
}
/* gets units from SI or nonSI class and split into base units */
public static ComplexAmount units(String s)
throws IllegalArgumentException, IllegalAccessException {
javax.measure.unit.Unit myObject;
try{
myObject = (Unit)javax.measure.unit.SI.class.getField(s).get(null);
}
catch(NoSuchFieldException e){
try{
myObject=(Unit)javax.measure.unit.NonSI.class.getField(s).get(null);
}
catch(NoSuchFieldException ee){
myObject=javax.measure.unit.Unit.valueOf(s);
}
}
Unit old=myObject;
// create set of split units
myObject=splitUnits(myObject);
// .to method does getStandardUnit
// convert old units to split units
return ComplexAmount.valueOf(Amount.valueOf(1.0, old).to(myObject));
}
}