Update
This commit is contained in:
parent
1e91428ce6
commit
7ad342b85c
BIN
res/font_big.ttf
Normal file
BIN
res/font_big.ttf
Normal file
Binary file not shown.
BIN
res/font_small.ttf
Normal file
BIN
res/font_small.ttf
Normal file
Binary file not shown.
BIN
res/skin.png
Normal file
BIN
res/skin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
res/skin.xcf
Normal file
BIN
res/skin.xcf
Normal file
Binary file not shown.
613
src/com/rits/cloning/Cloner.java
Normal file
613
src/com/rits/cloning/Cloner.java
Normal file
@ -0,0 +1,613 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Cloner: deep clone objects.
|
||||
*
|
||||
* This class is thread safe. One instance can be used by multiple threads on the same time.
|
||||
*
|
||||
* @author kostantinos.kougios
|
||||
* 18 Sep 2008
|
||||
*/
|
||||
public class Cloner {
|
||||
private final IInstantiationStrategy instantiationStrategy;
|
||||
private final Set<Class<?>> ignored = new HashSet<Class<?>>();
|
||||
private final Set<Class<?>> ignoredInstanceOf = new HashSet<Class<?>>();
|
||||
private final Set<Class<?>> nullInstead = new HashSet<Class<?>>();
|
||||
private final Map<Class<?>, IFastCloner> fastCloners = new HashMap<Class<?>, IFastCloner>();
|
||||
private final Map<Object, Boolean> ignoredInstances = new IdentityHashMap<Object, Boolean>();
|
||||
private final ConcurrentHashMap<Class<?>, List<Field>> fieldsCache = new ConcurrentHashMap<Class<?>, List<Field>>();
|
||||
|
||||
public IDumpCloned getDumpCloned() {
|
||||
return dumpCloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* provide a cloned classes dumper (so i.e. they can be logged or stored in a file
|
||||
* instead of the default behaviour which is to println(cloned) )
|
||||
*
|
||||
* @param dumpCloned an implementation of the interface which can dump the
|
||||
* cloned classes.
|
||||
*/
|
||||
public void setDumpCloned(IDumpCloned dumpCloned) {
|
||||
this.dumpCloned = dumpCloned;
|
||||
}
|
||||
|
||||
private IDumpCloned dumpCloned = null;
|
||||
private boolean cloningEnabled = true;
|
||||
private boolean nullTransient = false;
|
||||
private boolean cloneSynthetics = true;
|
||||
|
||||
public Cloner() {
|
||||
this.instantiationStrategy = ObjenesisInstantiationStrategy.getInstance();
|
||||
init();
|
||||
}
|
||||
|
||||
public Cloner(final IInstantiationStrategy instantiationStrategy) {
|
||||
this.instantiationStrategy = instantiationStrategy;
|
||||
init();
|
||||
}
|
||||
|
||||
public boolean isNullTransient() {
|
||||
return nullTransient;
|
||||
}
|
||||
|
||||
/**
|
||||
* this makes the cloner to set a transient field to null upon cloning.
|
||||
*
|
||||
* NOTE: primitive types can't be nulled. Their value will be set to default, i.e. 0 for int
|
||||
*
|
||||
* @param nullTransient true for transient fields to be nulled
|
||||
*/
|
||||
public void setNullTransient(final boolean nullTransient) {
|
||||
this.nullTransient = nullTransient;
|
||||
}
|
||||
|
||||
public void setCloneSynthetics(final boolean cloneSynthetics) {
|
||||
this.cloneSynthetics = cloneSynthetics;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
registerKnownJdkImmutableClasses();
|
||||
registerKnownConstants();
|
||||
registerFastCloners();
|
||||
}
|
||||
|
||||
/**
|
||||
* registers a std set of fast cloners.
|
||||
*/
|
||||
protected void registerFastCloners() {
|
||||
fastCloners.put(GregorianCalendar.class, new FastClonerCalendar());
|
||||
fastCloners.put(ArrayList.class, new FastClonerArrayList());
|
||||
fastCloners.put(LinkedList.class, new FastClonerLinkedList());
|
||||
fastCloners.put(HashSet.class, new FastClonerHashSet());
|
||||
fastCloners.put(HashMap.class, new FastClonerHashMap());
|
||||
fastCloners.put(TreeMap.class, new FastClonerTreeMap());
|
||||
fastCloners.put(ConcurrentHashMap.class, new FastClonerConcurrentHashMap());
|
||||
}
|
||||
|
||||
private IDeepCloner deepCloner = new IDeepCloner() {
|
||||
public <T> T deepClone(T o, Map<Object, Object> clones) {
|
||||
try {
|
||||
return cloneInternal(o, clones);
|
||||
} catch (IllegalAccessException e) {
|
||||
// just rethrow unchecked
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected Object fastClone(final Object o, final Map<Object, Object> clones) throws IllegalAccessException {
|
||||
final Class<? extends Object> c = o.getClass();
|
||||
final IFastCloner fastCloner = fastCloners.get(c);
|
||||
if (fastCloner != null) return fastCloner.clone(o, deepCloner, clones);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void registerConstant(final Object o) {
|
||||
ignoredInstances.put(o, true);
|
||||
}
|
||||
|
||||
public void registerConstant(final Class<?> c, final String privateFieldName) {
|
||||
try {
|
||||
final Field field = c.getDeclaredField(privateFieldName);
|
||||
field.setAccessible(true);
|
||||
final Object v = field.get(null);
|
||||
ignoredInstances.put(v, true);
|
||||
} catch (final SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (final NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* registers some known JDK immutable classes. Override this to register your
|
||||
* own list of jdk's immutable classes
|
||||
*/
|
||||
protected void registerKnownJdkImmutableClasses() {
|
||||
registerImmutable(String.class);
|
||||
registerImmutable(Integer.class);
|
||||
registerImmutable(Long.class);
|
||||
registerImmutable(Boolean.class);
|
||||
registerImmutable(Class.class);
|
||||
registerImmutable(Float.class);
|
||||
registerImmutable(Double.class);
|
||||
registerImmutable(Character.class);
|
||||
registerImmutable(Byte.class);
|
||||
registerImmutable(Short.class);
|
||||
registerImmutable(Void.class);
|
||||
|
||||
registerImmutable(BigDecimal.class);
|
||||
registerImmutable(BigInteger.class);
|
||||
registerImmutable(URI.class);
|
||||
registerImmutable(URL.class);
|
||||
registerImmutable(UUID.class);
|
||||
registerImmutable(Pattern.class);
|
||||
}
|
||||
|
||||
protected void registerKnownConstants() {
|
||||
// registering known constants of the jdk.
|
||||
registerStaticFields(TreeSet.class, HashSet.class, HashMap.class, TreeMap.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* registers all static fields of these classes. Those static fields won't be cloned when an instance
|
||||
* of the class is cloned.
|
||||
*
|
||||
* This is useful i.e. when a static field object is added into maps or sets. At that point, there is no
|
||||
* way for the cloner to know that it was static except if it is registered.
|
||||
*
|
||||
* @param classes array of classes
|
||||
*/
|
||||
public void registerStaticFields(final Class<?>... classes) {
|
||||
for (final Class<?> c : classes) {
|
||||
final List<Field> fields = allFields(c);
|
||||
for (final Field field : fields) {
|
||||
final int mods = field.getModifiers();
|
||||
if (Modifier.isStatic(mods) && !field.getType().isPrimitive()) {
|
||||
registerConstant(c, field.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* spring framework friendly version of registerStaticFields
|
||||
*
|
||||
* @param set a set of classes which will be scanned for static fields
|
||||
*/
|
||||
public void setExtraStaticFields(final Set<Class<?>> set) {
|
||||
registerStaticFields((Class<?>[]) set.toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* instances of classes that shouldn't be cloned can be registered using this method.
|
||||
*
|
||||
* @param c The class that shouldn't be cloned. That is, whenever a deep clone for
|
||||
* an object is created and c is encountered, the object instance of c will
|
||||
* be added to the clone.
|
||||
*/
|
||||
public void dontClone(final Class<?>... c) {
|
||||
for (final Class<?> cl : c) {
|
||||
ignored.add(cl);
|
||||
}
|
||||
}
|
||||
|
||||
public void dontCloneInstanceOf(final Class<?>... c) {
|
||||
for (final Class<?> cl : c) {
|
||||
ignoredInstanceOf.add(cl);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDontCloneInstanceOf(final Class<?>... c) {
|
||||
dontCloneInstanceOf(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* instead of cloning these classes will set the field to null
|
||||
*
|
||||
* @param c the classes to nullify during cloning
|
||||
*/
|
||||
public void nullInsteadOfClone(final Class<?>... c) {
|
||||
for (final Class<?> cl : c) {
|
||||
nullInstead.add(cl);
|
||||
}
|
||||
}
|
||||
|
||||
// spring framework friendly version of nullInsteadOfClone
|
||||
public void setExtraNullInsteadOfClone(final Set<Class<?>> set) {
|
||||
nullInstead.addAll(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* registers an immutable class. Immutable classes are not cloned.
|
||||
*
|
||||
* @param c the immutable class
|
||||
*/
|
||||
public void registerImmutable(final Class<?>... c) {
|
||||
for (final Class<?> cl : c) {
|
||||
ignored.add(cl);
|
||||
}
|
||||
}
|
||||
|
||||
// spring framework friendly version of registerImmutable
|
||||
public void setExtraImmutables(final Set<Class<?>> set) {
|
||||
ignored.addAll(set);
|
||||
}
|
||||
|
||||
public void registerFastCloner(final Class<?> c, final IFastCloner fastCloner) {
|
||||
if (fastCloners.containsKey(c)) throw new IllegalArgumentException(c + " already fast-cloned!");
|
||||
fastCloners.put(c, fastCloner);
|
||||
}
|
||||
|
||||
public void unregisterFastCloner(final Class<?> c) {
|
||||
fastCloners.remove(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new instance of c. Override to provide your own implementation
|
||||
*
|
||||
* @param <T> the type of c
|
||||
* @param c the class
|
||||
* @return a new instance of c
|
||||
*/
|
||||
protected <T> T newInstance(final Class<T> c) {
|
||||
return instantiationStrategy.newInstance(c);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fastCloneOrNewInstance(final Class<T> c) {
|
||||
try {
|
||||
final T fastClone = (T) fastClone(c, null);
|
||||
if (fastClone != null) return fastClone;
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return newInstance(c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* deep clones "o".
|
||||
*
|
||||
* @param <T> the type of "o"
|
||||
* @param o the object to be deep-cloned
|
||||
* @return a deep-clone of "o".
|
||||
*/
|
||||
public <T> T deepClone(final T o) {
|
||||
if (o == null) return null;
|
||||
if (!cloningEnabled) return o;
|
||||
if (dumpCloned != null) {
|
||||
dumpCloned.startCloning(o.getClass());
|
||||
}
|
||||
final Map<Object, Object> clones = new IdentityHashMap<Object, Object>(16);
|
||||
try {
|
||||
return cloneInternal(o, clones);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new CloningException("error during cloning of " + o, e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T deepCloneDontCloneInstances(final T o, final Object... dontCloneThese) {
|
||||
if (o == null) return null;
|
||||
if (!cloningEnabled) return o;
|
||||
if (dumpCloned != null) {
|
||||
dumpCloned.startCloning(o.getClass());
|
||||
}
|
||||
final Map<Object, Object> clones = new IdentityHashMap<Object, Object>(16);
|
||||
for (final Object dc : dontCloneThese) {
|
||||
clones.put(dc, dc);
|
||||
}
|
||||
try {
|
||||
return cloneInternal(o, clones);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new CloningException("error during cloning of " + o, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shallow clones "o". This means that if c=shallowClone(o) then
|
||||
* c!=o. Any change to c won't affect o.
|
||||
*
|
||||
* @param <T> the type of o
|
||||
* @param o the object to be shallow-cloned
|
||||
* @return a shallow clone of "o"
|
||||
*/
|
||||
public <T> T shallowClone(final T o) {
|
||||
if (o == null) return null;
|
||||
if (!cloningEnabled) return o;
|
||||
try {
|
||||
return cloneInternal(o, null);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new CloningException("error during cloning of " + o, e);
|
||||
}
|
||||
}
|
||||
|
||||
// caches immutables for quick reference
|
||||
private final ConcurrentHashMap<Class<?>, Boolean> immutables = new ConcurrentHashMap<Class<?>, Boolean>();
|
||||
private boolean cloneAnonymousParent = true;
|
||||
|
||||
/**
|
||||
* override this to decide if a class is immutable. Immutable classes are not cloned.
|
||||
*
|
||||
* @param clz the class under check
|
||||
* @return true to mark clz as immutable and skip cloning it
|
||||
*/
|
||||
protected boolean considerImmutable(final Class<?> clz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Class<?> getImmutableAnnotation() {
|
||||
return Immutable.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* decides if a class is to be considered immutable or not
|
||||
*
|
||||
* @param clz the class under check
|
||||
* @return true if the clz is considered immutable
|
||||
*/
|
||||
private boolean isImmutable(final Class<?> clz) {
|
||||
final Boolean isIm = immutables.get(clz);
|
||||
if (isIm != null) return isIm;
|
||||
if (considerImmutable(clz)) return true;
|
||||
|
||||
final Class<?> immutableAnnotation = getImmutableAnnotation();
|
||||
for (final Annotation annotation : clz.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType() == immutableAnnotation) {
|
||||
immutables.put(clz, Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Class<?> c = clz.getSuperclass();
|
||||
while (c != null && c != Object.class) {
|
||||
for (final Annotation annotation : c.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType() == Immutable.class) {
|
||||
final Immutable im = (Immutable) annotation;
|
||||
if (im.subClass()) {
|
||||
immutables.put(clz, Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
immutables.put(clz, Boolean.FALSE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T cloneInternal(final T o, final Map<Object, Object> clones) throws IllegalAccessException {
|
||||
if (o == null) return null;
|
||||
if (o == this) return null; // don't clone the cloner!
|
||||
if (ignoredInstances.containsKey(o)) return o;
|
||||
if (o instanceof Enum) return o;
|
||||
final Class<T> clz = (Class<T>) o.getClass();
|
||||
// skip cloning ignored classes
|
||||
if (nullInstead.contains(clz)) return null;
|
||||
if (ignored.contains(clz)) return o;
|
||||
for (final Class<?> iClz : ignoredInstanceOf) {
|
||||
if (iClz.isAssignableFrom(clz)) return o;
|
||||
}
|
||||
if (isImmutable(clz)) return o;
|
||||
if (o instanceof IFreezable) {
|
||||
final IFreezable f = (IFreezable) o;
|
||||
if (f.isFrozen()) return o;
|
||||
}
|
||||
final Object clonedPreviously = clones != null ? clones.get(o) : null;
|
||||
if (clonedPreviously != null) return (T) clonedPreviously;
|
||||
|
||||
final Object fastClone = fastClone(o, clones);
|
||||
if (fastClone != null) {
|
||||
if (clones != null) {
|
||||
clones.put(o, fastClone);
|
||||
}
|
||||
return (T) fastClone;
|
||||
}
|
||||
|
||||
if (dumpCloned != null) {
|
||||
dumpCloned.startCloning(o.getClass());
|
||||
}
|
||||
if (clz.isArray()) {
|
||||
return cloneArray(o, clones);
|
||||
}
|
||||
|
||||
return cloneObject(o, clones, clz);
|
||||
}
|
||||
|
||||
// clones o, no questions asked!
|
||||
private <T> T cloneObject(T o, Map<Object, Object> clones, Class<T> clz) throws IllegalAccessException {
|
||||
final T newInstance = newInstance(clz);
|
||||
if (clones != null) {
|
||||
clones.put(o, newInstance);
|
||||
}
|
||||
final List<Field> fields = allFields(clz);
|
||||
for (final Field field : fields) {
|
||||
final int modifiers = field.getModifiers();
|
||||
if (!Modifier.isStatic(modifiers)) {
|
||||
if ( ! (nullTransient && Modifier.isTransient(modifiers)) ) {
|
||||
// request by Jonathan : transient fields can be null-ed
|
||||
final Object fieldObject = field.get(o);
|
||||
final boolean shouldClone = (cloneSynthetics || !field.isSynthetic()) && (cloneAnonymousParent || !isAnonymousParent(field));
|
||||
final Object fieldObjectClone = clones != null ? (shouldClone ? cloneInternal(fieldObject, clones) : fieldObject) : fieldObject;
|
||||
field.set(newInstance, fieldObjectClone);
|
||||
if (dumpCloned != null && fieldObjectClone != fieldObject) {
|
||||
dumpCloned.cloning(field, o.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T cloneArray(T o, Map<Object, Object> clones) throws IllegalAccessException {
|
||||
final Class<T> clz = (Class<T>) o.getClass();
|
||||
final int length = Array.getLength(o);
|
||||
final T newInstance = (T) Array.newInstance(clz.getComponentType(), length);
|
||||
if (clones != null) {
|
||||
clones.put(o, newInstance);
|
||||
}
|
||||
if(clz.getComponentType().isPrimitive() || isImmutable(clz.getComponentType())) {
|
||||
System.arraycopy(o, 0, newInstance, 0, length);
|
||||
} else {
|
||||
for (int i = 0; i < length; i++) {
|
||||
final Object v = Array.get(o, i);
|
||||
final Object clone = clones != null ? cloneInternal(v, clones) : v;
|
||||
Array.set(newInstance, i, clone);
|
||||
}
|
||||
}
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
private boolean isAnonymousParent(final Field field) {
|
||||
return "this$0".equals(field.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* copies all properties from src to dest. Src and dest can be of different class, provided they contain same field names/types
|
||||
*
|
||||
* @param src the source object
|
||||
* @param dest the destination object which must contain as minimum all the fields of src
|
||||
*/
|
||||
public <T, E extends T> void copyPropertiesOfInheritedClass(final T src, final E dest) {
|
||||
if (src == null) throw new IllegalArgumentException("src can't be null");
|
||||
if (dest == null) throw new IllegalArgumentException("dest can't be null");
|
||||
final Class<? extends Object> srcClz = src.getClass();
|
||||
final Class<? extends Object> destClz = dest.getClass();
|
||||
if (srcClz.isArray()) {
|
||||
if (!destClz.isArray())
|
||||
throw new IllegalArgumentException("can't copy from array to non-array class " + destClz);
|
||||
final int length = Array.getLength(src);
|
||||
for (int i = 0; i < length; i++) {
|
||||
final Object v = Array.get(src, i);
|
||||
Array.set(dest, i, v);
|
||||
}
|
||||
return;
|
||||
}
|
||||
final List<Field> fields = allFields(srcClz);
|
||||
final List<Field> destFields = allFields(dest.getClass());
|
||||
for (final Field field : fields) {
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
try {
|
||||
final Object fieldObject = field.get(src);
|
||||
field.setAccessible(true);
|
||||
if (destFields.contains(field)) {
|
||||
field.set(dest, fieldObject);
|
||||
}
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reflection utils
|
||||
*/
|
||||
private void addAll(final List<Field> l, final Field[] fields) {
|
||||
for (final Field field : fields) {
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
l.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reflection utils, override this to choose which fields to clone
|
||||
*/
|
||||
protected List<Field> allFields(final Class<?> c) {
|
||||
List<Field> l = fieldsCache.get(c);
|
||||
if (l == null) {
|
||||
l = new LinkedList<Field>();
|
||||
final Field[] fields = c.getDeclaredFields();
|
||||
addAll(l, fields);
|
||||
Class<?> sc = c;
|
||||
while ((sc = sc.getSuperclass()) != Object.class && sc != null) {
|
||||
addAll(l, sc.getDeclaredFields());
|
||||
}
|
||||
fieldsCache.putIfAbsent(c, l);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean isDumpClonedClasses() {
|
||||
return dumpCloned != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* will println() all cloned classes. Useful for debugging only. Use
|
||||
* setDumpCloned() if you want to control where to print the cloned
|
||||
* classes.
|
||||
*
|
||||
* @param dumpClonedClasses true to enable printing all cloned classes
|
||||
*/
|
||||
public void setDumpClonedClasses(final boolean dumpClonedClasses) {
|
||||
if (dumpClonedClasses) {
|
||||
dumpCloned = new IDumpCloned() {
|
||||
public void startCloning(Class<?> clz) {
|
||||
System.out.println("clone>" + clz);
|
||||
}
|
||||
|
||||
public void cloning(Field field, Class<?> clz) {
|
||||
System.out.println("cloned field>" + field + " -- of class " + clz);
|
||||
}
|
||||
};
|
||||
} else dumpCloned = null;
|
||||
}
|
||||
|
||||
public boolean isCloningEnabled() {
|
||||
return cloningEnabled;
|
||||
}
|
||||
|
||||
public void setCloningEnabled(final boolean cloningEnabled) {
|
||||
this.cloningEnabled = cloningEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* if false, anonymous classes parent class won't be cloned. Default is true
|
||||
*/
|
||||
public void setCloneAnonymousParent(final boolean cloneAnonymousParent) {
|
||||
this.cloneAnonymousParent = cloneAnonymousParent;
|
||||
}
|
||||
|
||||
public boolean isCloneAnonymousParent() {
|
||||
return cloneAnonymousParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a standard cloner instance, will do for most use cases
|
||||
*/
|
||||
public static Cloner standard() {
|
||||
return new Cloner();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if Cloner lib is in a shared jar folder for a container (i.e. tomcat/shared), then
|
||||
* this method is preferable in order to instantiate cloner. Please
|
||||
* see https://code.google.com/p/cloning/issues/detail?id=23
|
||||
*/
|
||||
public static Cloner shared() {
|
||||
return new Cloner(new ObjenesisInstantiationStrategy());
|
||||
}
|
||||
|
||||
}
|
20
src/com/rits/cloning/CloningException.java
Normal file
20
src/com/rits/cloning/CloningException.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
/**
|
||||
* thrown if cloning fails
|
||||
*
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 18 Jan 2009
|
||||
*/
|
||||
public class CloningException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 3815175312001146867L;
|
||||
|
||||
public CloningException(final String message, final Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
|
||||
}
|
||||
|
||||
}
|
25
src/com/rits/cloning/FastClonerArrayList.java
Normal file
25
src/com/rits/cloning/FastClonerArrayList.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
public class FastClonerArrayList implements IFastCloner
|
||||
{
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final ArrayList al = (ArrayList) t;
|
||||
final ArrayList l = new ArrayList(al.size());
|
||||
for (final Object o : al)
|
||||
{
|
||||
final Object cloneInternal = cloner.deepClone(o, clones);
|
||||
l.add(cloneInternal);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
}
|
22
src/com/rits/cloning/FastClonerCalendar.java
Normal file
22
src/com/rits/cloning/FastClonerCalendar.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
public class FastClonerCalendar implements IFastCloner
|
||||
{
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final GregorianCalendar gc = new GregorianCalendar();
|
||||
Calendar c = (Calendar) t;
|
||||
gc.setTimeInMillis(c.getTimeInMillis());
|
||||
gc.setTimeZone((TimeZone) c.getTimeZone().clone());
|
||||
return gc;
|
||||
}
|
||||
}
|
26
src/com/rits/cloning/FastClonerConcurrentHashMap.java
Normal file
26
src/com/rits/cloning/FastClonerConcurrentHashMap.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 18 Oct 2011
|
||||
*/
|
||||
public class FastClonerConcurrentHashMap implements IFastCloner
|
||||
{
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final ConcurrentHashMap<Object, Object> m = (ConcurrentHashMap) t;
|
||||
final ConcurrentHashMap result = new ConcurrentHashMap();
|
||||
for (final Map.Entry e : m.entrySet())
|
||||
{
|
||||
final Object key = cloner.deepClone(e.getKey(), clones);
|
||||
final Object value = cloner.deepClone(e.getValue(), clones);
|
||||
|
||||
result.put(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
26
src/com/rits/cloning/FastClonerCustomCollection.java
Normal file
26
src/com/rits/cloning/FastClonerCustomCollection.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public abstract class FastClonerCustomCollection<T extends Collection> implements IFastCloner
|
||||
{
|
||||
public abstract T getInstance(T o);
|
||||
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final T c = getInstance((T) t);
|
||||
final T l = (T) t;
|
||||
for (final Object o : l)
|
||||
{
|
||||
final Object clone = cloner.deepClone(o, clones);
|
||||
c.add(clone);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
28
src/com/rits/cloning/FastClonerCustomMap.java
Normal file
28
src/com/rits/cloning/FastClonerCustomMap.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public abstract class FastClonerCustomMap<T extends Map> implements IFastCloner
|
||||
{
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final T m = (T) t;
|
||||
final T result = getInstance((T) t);
|
||||
final Set<Map.Entry<Object, Object>> entrySet = m.entrySet();
|
||||
for (final Map.Entry e : entrySet)
|
||||
{
|
||||
final Object key = cloner.deepClone(e.getKey(), clones);
|
||||
final Object value = cloner.deepClone(e.getValue(), clones);
|
||||
result.put(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract T getInstance(T t);
|
||||
}
|
26
src/com/rits/cloning/FastClonerHashMap.java
Normal file
26
src/com/rits/cloning/FastClonerHashMap.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
public class FastClonerHashMap implements IFastCloner
|
||||
{
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final HashMap<Object, Object> m = (HashMap) t;
|
||||
final HashMap result = new HashMap();
|
||||
for (final Map.Entry e : m.entrySet())
|
||||
{
|
||||
final Object key = cloner.deepClone(e.getKey(), clones);
|
||||
final Object value = cloner.deepClone(e.getValue(), clones);
|
||||
|
||||
result.put(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
24
src/com/rits/cloning/FastClonerHashSet.java
Normal file
24
src/com/rits/cloning/FastClonerHashSet.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
public class FastClonerHashSet implements IFastCloner
|
||||
{
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final HashSet al = (HashSet) t;
|
||||
final HashSet l = new HashSet();
|
||||
for (final Object o : al)
|
||||
{
|
||||
final Object cloneInternal = cloner.deepClone(o, clones);
|
||||
l.add(cloneInternal);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
24
src/com/rits/cloning/FastClonerLinkedList.java
Normal file
24
src/com/rits/cloning/FastClonerLinkedList.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
public class FastClonerLinkedList implements IFastCloner
|
||||
{
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final LinkedList al = (LinkedList) t;
|
||||
final LinkedList l = new LinkedList();
|
||||
for (final Object o : al)
|
||||
{
|
||||
final Object cloneInternal = cloner.deepClone(o, clones);
|
||||
l.add(cloneInternal);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
25
src/com/rits/cloning/FastClonerTreeMap.java
Normal file
25
src/com/rits/cloning/FastClonerTreeMap.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 21 May 2009
|
||||
*/
|
||||
public class FastClonerTreeMap implements IFastCloner
|
||||
{
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Object clone(final Object t, final IDeepCloner cloner, final Map<Object, Object> clones) {
|
||||
final TreeMap<Object, Object> m = (TreeMap) t;
|
||||
final TreeMap result = new TreeMap(m.comparator());
|
||||
for (final Map.Entry e : m.entrySet())
|
||||
{
|
||||
final Object key = cloner.deepClone(e.getKey(), clones);
|
||||
final Object value = cloner.deepClone(e.getValue(), clones);
|
||||
result.put(key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
20
src/com/rits/cloning/IDeepCloner.java
Normal file
20
src/com/rits/cloning/IDeepCloner.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* used by fast cloners to deep clone objects
|
||||
*
|
||||
* @author kostas.kougios Date 24/06/14
|
||||
*/
|
||||
public interface IDeepCloner {
|
||||
/**
|
||||
* deep clones o
|
||||
*
|
||||
* @param o the object to be deep cloned
|
||||
* @param clones pass on the same map from IFastCloner
|
||||
* @param <T> the type of o
|
||||
* @return a clone of o
|
||||
*/
|
||||
<T> T deepClone(final T o, final Map<Object, Object> clones);
|
||||
}
|
14
src/com/rits/cloning/IDumpCloned.java
Normal file
14
src/com/rits/cloning/IDumpCloned.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @author: kostas.kougios
|
||||
* Date: 06/08/13
|
||||
*/
|
||||
public interface IDumpCloned
|
||||
{
|
||||
void startCloning(Class<?> clz);
|
||||
|
||||
void cloning(Field field, Class<?> clz);
|
||||
}
|
14
src/com/rits/cloning/IFastCloner.java
Normal file
14
src/com/rits/cloning/IFastCloner.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* allows a custom cloner to be created for a specific class.
|
||||
* (it has to be registered with Cloner)
|
||||
*
|
||||
* @author kostantinos.kougios
|
||||
* 21 May 2009
|
||||
*/
|
||||
public interface IFastCloner {
|
||||
public Object clone(Object t, IDeepCloner cloner, Map<Object, Object> clones);
|
||||
}
|
12
src/com/rits/cloning/IFreezable.java
Normal file
12
src/com/rits/cloning/IFreezable.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 15 Nov 2010
|
||||
*/
|
||||
public interface IFreezable
|
||||
{
|
||||
public boolean isFrozen();
|
||||
|
||||
}
|
11
src/com/rits/cloning/IInstantiationStrategy.java
Normal file
11
src/com/rits/cloning/IInstantiationStrategy.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 17 Jul 2012
|
||||
*/
|
||||
public interface IInstantiationStrategy
|
||||
{
|
||||
<T> T newInstance(final Class<T> c);
|
||||
}
|
25
src/com/rits/cloning/Immutable.java
Normal file
25
src/com/rits/cloning/Immutable.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* marks the specific class as immutable and the cloner avoids cloning it
|
||||
*
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 24 Mar 2011
|
||||
*/
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface Immutable
|
||||
{
|
||||
/**
|
||||
* by default all subclasses of the @Immutable class are not immutable. This can override it.
|
||||
* @return true for subclasses of @Immutable class to be regarded as immutable from the cloner
|
||||
*/
|
||||
boolean subClass() default false;
|
||||
}
|
26
src/com/rits/cloning/ObjenesisInstantiationStrategy.java
Normal file
26
src/com/rits/cloning/ObjenesisInstantiationStrategy.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.rits.cloning;
|
||||
|
||||
import org.objenesis.Objenesis;
|
||||
import org.objenesis.ObjenesisStd;
|
||||
|
||||
/**
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 17 Jul 2012
|
||||
*/
|
||||
public class ObjenesisInstantiationStrategy implements IInstantiationStrategy
|
||||
{
|
||||
private final Objenesis objenesis = new ObjenesisStd();
|
||||
|
||||
public <T> T newInstance(Class<T> c)
|
||||
{
|
||||
return objenesis.newInstance(c);
|
||||
}
|
||||
|
||||
private static ObjenesisInstantiationStrategy instance = new ObjenesisInstantiationStrategy();
|
||||
|
||||
public static ObjenesisInstantiationStrategy getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
73
src/com/rits/perspectives/Perspectives.java
Normal file
73
src/com/rits/perspectives/Perspectives.java
Normal file
@ -0,0 +1,73 @@
|
||||
package com.rits.perspectives;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.rits.cloning.Cloner;
|
||||
|
||||
/**
|
||||
* Perspectives: an object instance of a class behaving differently according to the "view angle".
|
||||
*
|
||||
* @author kostantinos.kougios
|
||||
*
|
||||
* 30 Nov 2009
|
||||
*/
|
||||
public class Perspectives
|
||||
{
|
||||
private final Cloner cloner;
|
||||
|
||||
public Perspectives(final Cloner cloner)
|
||||
{
|
||||
this.cloner = cloner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample: if o is an instance of Product and c is OrderedProduct.class then this returns
|
||||
* and instance of OrderedProduct.class which has equal field values to those of the instance of Product.
|
||||
* In other words, the returned instance of OrderedProduct.class is the Product instance from the perspective
|
||||
* of an OrderedProduct
|
||||
*
|
||||
* View an object o from the perspective of class c. (view o as an instance of c). c must be instanceof o.getClass()
|
||||
*
|
||||
* @param <T> the object
|
||||
* @param <E> this will be the returned type and it must be instanceof T. All properties of o will be copied to this instance.
|
||||
* @param c the class of E. This is used to generate new instances of c
|
||||
* @param o the object that must be viewed from a different perspective
|
||||
* @return the E perspective of o
|
||||
*/
|
||||
public <T, E extends T> E viewAs(final Class<E> c, final T o)
|
||||
{
|
||||
if (o == null) return null;
|
||||
if (o instanceof Collection<?>) throw new IllegalArgumentException("for collections please use viewCollectionAs() method. Invalid object " + o);
|
||||
final E newInstance = cloner.fastCloneOrNewInstance(c);
|
||||
cloner.copyPropertiesOfInheritedClass(o, newInstance);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample: if o is a [ Products extends LinkedList<Product> ] then the returned instance
|
||||
* is a [ OrderedProducts extends LinkedList<OrderedProduct> ].
|
||||
*
|
||||
* View a collection o from the perspective of collection E.
|
||||
*
|
||||
* NOTE: order of the items might not be preserved, depending on the collection type
|
||||
*
|
||||
* @param <T> the type of the collection o
|
||||
* @param <I> the type of the elements of the collection o
|
||||
* @param <E> the type of the perspective collection
|
||||
* @param <NI> the type of the perspective's elements
|
||||
* @param newCollection the collection to which the adapted instances should be added
|
||||
* @param currentCollection the collection with the instances to be adapted
|
||||
* @param perspectiveCollectionItemClass the class of the NI
|
||||
* @return E, the collection from a different perspective or null if currentCollection is null
|
||||
*/
|
||||
public <I, NI extends I, T extends Collection<I>, E extends Collection<NI>> E viewCollectionAs(final E newCollection, final Class<NI> perspectiveCollectionItemClass, final T currentCollection)
|
||||
{
|
||||
if (currentCollection == null) return null;
|
||||
for (final I item : currentCollection)
|
||||
{
|
||||
final NI newItem = viewAs(perspectiveCollectionItemClass, item);
|
||||
newCollection.add(newItem);
|
||||
}
|
||||
return newCollection;
|
||||
}
|
||||
}
|
744
src/org/nevec/rjm/NumeroAvanzato.java
Normal file
744
src/org/nevec/rjm/NumeroAvanzato.java
Normal file
@ -0,0 +1,744 @@
|
||||
package org.nevec.rjm;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.MathContext;
|
||||
import java.security.ProviderException;
|
||||
|
||||
import org.warpgate.pi.calculator.Errore;
|
||||
import org.warpgate.pi.calculator.Incognita;
|
||||
import org.warpgate.pi.calculator.Incognite;
|
||||
import org.warpgate.pi.calculator.Utils;
|
||||
|
||||
/**
|
||||
* Square roots on the real line. These represent numbers which are a product of
|
||||
* a (signed) fraction by a square root of a non-negative fraction. This might
|
||||
* be extended to values on the imaginary axis by allowing negative values
|
||||
* underneath the square root, but this is not yet implemented.
|
||||
*
|
||||
* @since 2011-02-12
|
||||
* @author Richard J. Mathar
|
||||
*/
|
||||
public class NumeroAvanzato implements Cloneable {
|
||||
/**
|
||||
* The value of zero.
|
||||
*/
|
||||
public static final NumeroAvanzato ZERO = new NumeroAvanzato();
|
||||
|
||||
/**
|
||||
* The value of one.
|
||||
*/
|
||||
public static final NumeroAvanzato ONE = new NumeroAvanzato(Rational.ONE, Rational.ONE);
|
||||
/**
|
||||
* Prefactor
|
||||
*/
|
||||
Rational pref;
|
||||
|
||||
private Incognite incognitex;
|
||||
|
||||
private Incognite incognitey;
|
||||
|
||||
private Incognite incognitez;
|
||||
|
||||
/**
|
||||
* The number underneath the square root, always non-negative. The
|
||||
* mathematical object has the value pref*sqrt(disc).
|
||||
*/
|
||||
Rational disc;
|
||||
|
||||
/**
|
||||
* Default ctor, which represents the zero.
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato() {
|
||||
pref = Rational.ZERO;
|
||||
disc = Rational.ZERO;
|
||||
incognitex = new Incognite();
|
||||
incognitey = new Incognite();
|
||||
incognitez = new Incognite();
|
||||
}
|
||||
|
||||
/**
|
||||
* ctor given the prefactor and the basis of the root. This creates an
|
||||
* object of value a*sqrt(b).
|
||||
*
|
||||
* @param a
|
||||
* the prefactor.
|
||||
* @param b
|
||||
* the discriminant.
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato(Rational a, Rational b) {
|
||||
this.pref = a;
|
||||
/*
|
||||
* reject attempts to use a negative b
|
||||
*/
|
||||
if (b.signum() < 0)
|
||||
throw new ProviderException("Not implemented: imaginary surds");
|
||||
this.disc = b;
|
||||
incognitex = new Incognite();
|
||||
incognitey = new Incognite();
|
||||
incognitez = new Incognite();
|
||||
try {
|
||||
normalize();
|
||||
normalizeG();
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public NumeroAvanzato(Rational a, Rational b, Incognite x, Incognite y, Incognite z) {
|
||||
this.pref = a;
|
||||
/*
|
||||
* reject attempts to use a negative b
|
||||
*/
|
||||
if (b.signum() < 0)
|
||||
throw new ProviderException("Not implemented: imaginary surds");
|
||||
this.disc = b;
|
||||
incognitex = x;
|
||||
incognitey = y;
|
||||
incognitez = z;
|
||||
try {
|
||||
normalize();
|
||||
normalizeG();
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ctor given the numerator and denominator of the root. This creates an
|
||||
* object of value sqrt(a/b).
|
||||
*
|
||||
* @param a
|
||||
* the numerator
|
||||
* @param b
|
||||
* the denominator.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato(int a, int b) {
|
||||
this(Rational.ONE, new Rational(a, b));
|
||||
}
|
||||
|
||||
/**
|
||||
* ctor given the value under the root. This creates an object of value
|
||||
* sqrt(a).
|
||||
*
|
||||
* @param a
|
||||
* the discriminant.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato(BigInteger a) {
|
||||
this(Rational.ONE, new Rational(a, BigInteger.ONE));
|
||||
}
|
||||
|
||||
public NumeroAvanzato(Rational a) {
|
||||
this(Rational.ONE, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a deep copy.
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato clone() {
|
||||
Rational fclon = pref.clone();
|
||||
Rational dclon = disc.clone();
|
||||
Incognite incognitexb = incognitex;
|
||||
Incognite incogniteyb = incognitey;
|
||||
Incognite incognitezb = incognitez;
|
||||
/*
|
||||
* the main intent here is to bypass any attempt to reduce the
|
||||
* discriminant by figuring out the square-free part in normalize(),
|
||||
* which has already done in the current copy of the number.
|
||||
*/
|
||||
NumeroAvanzato cl = new NumeroAvanzato();
|
||||
cl.pref = fclon;
|
||||
cl.disc = dclon;
|
||||
cl.incognitex = incognitexb;
|
||||
cl.incognitey = incogniteyb;
|
||||
cl.incognitez = incognitezb;
|
||||
return cl;
|
||||
} /* NumeroAvanzato.clone */
|
||||
|
||||
/**
|
||||
* Add two surds of compatible discriminant.
|
||||
*
|
||||
* @param val
|
||||
* The value to be added to this.
|
||||
*/
|
||||
|
||||
public NumeroAvanzatoVec add(final NumeroAvanzato val) {
|
||||
// zero plus somethings yields something
|
||||
if (signum() == 0)
|
||||
return new NumeroAvanzatoVec(val);
|
||||
else if (val.signum() == 0)
|
||||
return new NumeroAvanzatoVec(this);
|
||||
else
|
||||
// let the ctor of NumeroAvanzatoVec to the work
|
||||
return new NumeroAvanzatoVec(this, val);
|
||||
} /* NumeroAvanzato.add */
|
||||
|
||||
/**
|
||||
* Multiply by another square root.
|
||||
*
|
||||
* @param val
|
||||
* a second number of this type.
|
||||
* @return the product of this with the val.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato multiply(final NumeroAvanzato val) {
|
||||
return new NumeroAvanzato(pref.multiply(val.pref), disc.multiply(val.disc), incognitex.multiply(val.incognitex),
|
||||
incognitey.multiply(val.incognitey), incognitez.multiply(val.incognitez));
|
||||
} /* NumeroAvanzato.multiply */
|
||||
|
||||
/**
|
||||
* Multiply by a rational number.
|
||||
*
|
||||
* @param val
|
||||
* the factor.
|
||||
* @return the product of this with the val.
|
||||
* @since 2011-02-15
|
||||
*/
|
||||
public NumeroAvanzato multiply(final Rational val) {
|
||||
return new NumeroAvanzato(pref.multiply(val), disc, incognitex, incognitey, incognitez);
|
||||
} /* NumeroAvanzato.multiply */
|
||||
|
||||
/**
|
||||
* Multiply by a BigInteger.
|
||||
*
|
||||
* @param val
|
||||
* a second number.
|
||||
* @return the product of this with the value.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato multiply(final BigInteger val) {
|
||||
return new NumeroAvanzato(pref.multiply(val), disc, incognitex, incognitey, incognitez);
|
||||
} /* NumeroAvanzato.multiply */
|
||||
|
||||
/**
|
||||
* Multiply by an integer.
|
||||
*
|
||||
* @param val
|
||||
* a second number.
|
||||
* @return the product of this with the value.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato multiply(final int val) {
|
||||
BigInteger tmp = new BigInteger("" + val);
|
||||
return multiply(tmp);
|
||||
} /* NumeroAvanzato.multiply */
|
||||
|
||||
/**
|
||||
* Compute the square.
|
||||
*
|
||||
* @return this value squared.
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato pow2() throws Errore {
|
||||
NumeroAvanzato res = new NumeroAvanzato();
|
||||
BigInteger a = pref.a;
|
||||
BigInteger b = pref.b;
|
||||
BigInteger c = disc.a;
|
||||
BigInteger d = disc.b;
|
||||
res.pref = new Rational(a.pow(2).multiply(c).multiply(d), b.pow(2).multiply(d));
|
||||
res.disc = new Rational(0, 1);
|
||||
res.normalize();
|
||||
res.incognitex = incognitex;
|
||||
res.incognitey = incognitey.multiply(incognitey);
|
||||
res.incognitez = incognitez.multiply(incognitez);
|
||||
return res;
|
||||
} /* NumeroAvanzato.sqr */
|
||||
|
||||
/**
|
||||
* Divide by another square root.
|
||||
*
|
||||
* @param val
|
||||
* A second number of this type.
|
||||
* @return The value of this/val
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato divide(final NumeroAvanzato val) throws Errore {
|
||||
if (val.signum() == 0)
|
||||
throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
|
||||
NumeroAvanzato result = new NumeroAvanzato(pref.divide(val.pref), disc.divide(val.disc));
|
||||
result.incognitex = incognitex.divide(val.incognitex);
|
||||
result.incognitey = incognitey.divide(val.incognitey);
|
||||
result.incognitez = incognitez.divide(val.incognitez);
|
||||
result.normalize();
|
||||
return result;
|
||||
} /* NumeroAvanzato.divide */
|
||||
|
||||
private String toFancyString() throws Errore {
|
||||
return new NumeroAvanzatoVec(this).toFancyString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide by an integer.
|
||||
*
|
||||
* @param val
|
||||
* a second number.
|
||||
* @return the value of this/val
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato divide(final BigInteger val) throws Errore {
|
||||
if (val.signum() == 0)
|
||||
throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
|
||||
return new NumeroAvanzato(pref.divide(val), disc);
|
||||
} /* NumeroAvanzato.divide */
|
||||
|
||||
/**
|
||||
* Divide by an integer.
|
||||
*
|
||||
* @param val
|
||||
* A second number.
|
||||
* @return The value of this/val
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato divide(int val) throws Errore {
|
||||
if (val == 0)
|
||||
throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
|
||||
return new NumeroAvanzato(pref.divide(val), disc);
|
||||
} /* NumeroAvanzato.divide */
|
||||
|
||||
/**
|
||||
* Compute the negative.
|
||||
*
|
||||
* @return -this.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato negate() {
|
||||
/*
|
||||
* This is trying to be quick, avoiding normalize(), by toggling the
|
||||
* sign in a clone()
|
||||
*/
|
||||
NumeroAvanzato n = clone();
|
||||
n.pref = n.pref.negate();
|
||||
return n;
|
||||
} /* NumeroAvanzato.negate */
|
||||
|
||||
/**
|
||||
* Absolute value.
|
||||
*
|
||||
* @return The absolute (non-negative) value of this.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzato abs() {
|
||||
return new NumeroAvanzato(pref.abs(), disc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the value of this with another constant.
|
||||
*
|
||||
* @param val
|
||||
* the other constant to compare with
|
||||
* @return -1, 0 or 1 if this number is numerically less than, equal to, or
|
||||
* greater than val.
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public int signumComparedTo(final NumeroAvanzato val) throws Errore {
|
||||
/*
|
||||
* Since we keep the discriminant positive, the rough estimate comes
|
||||
* from comparing the signs of the prefactors.
|
||||
*/
|
||||
final int sig = signum();
|
||||
final int sigv = val.signum();
|
||||
if (sig < 0 && sigv >= 0)
|
||||
return -1;
|
||||
if (sig > 0 && sigv <= 0)
|
||||
return 1;
|
||||
if (sig == 0 && sigv == 0)
|
||||
return 0;
|
||||
if (sig == 0 && sigv > 0)
|
||||
return -1;
|
||||
if (sig == 0 && sigv < 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Work out the cases of equal sign. Compare absolute values by
|
||||
* comparison of the squares which is forwarded to the comparison of the
|
||||
* Rational class.
|
||||
*/
|
||||
final Rational this2 = pow2().pref;
|
||||
final Rational val2 = val.pow2().pref;
|
||||
final int c2 = this2.compareTo(val2);
|
||||
if (c2 == 0)
|
||||
return 0;
|
||||
/*
|
||||
* If both values have negative sign, the one with the smaller square is
|
||||
* the larger number.
|
||||
*/
|
||||
else if (sig > 0 && c2 > 0 || sig < 0 && c2 < 0)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
} /* NumeroAvanzato.compareTo */
|
||||
|
||||
/**
|
||||
* Return a string in the format (number/denom)*()^(1/2). If the
|
||||
* discriminant equals 1, print just the prefactor.
|
||||
*
|
||||
* @return the human-readable version in base 10
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public String toString() {
|
||||
try {
|
||||
return toFancyString();
|
||||
} catch (Errore e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
/*
|
||||
if (disc.compareTo(Rational.ONE) != 0 && disc.compareTo(Rational.ZERO) != 0)
|
||||
return ("(" + pref.toString() + ")*(" + disc.toString() + ")^(1/2)");
|
||||
else
|
||||
return pref.toString();
|
||||
*/
|
||||
return "err";
|
||||
} /* NumeroAvanzato.toString */
|
||||
|
||||
/**
|
||||
* Return a double value representation.
|
||||
*
|
||||
* @return The value with double precision.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public double doubleValue() {
|
||||
/*
|
||||
* First compute the square to prevent overflows if the two pieces of
|
||||
* the prefactor and the discriminant are of very different magnitude.
|
||||
*/
|
||||
Rational p2 = pref.pow(2).multiply(disc);
|
||||
System.out.println("dv sq " + p2.toString());
|
||||
double res = p2.doubleValue();
|
||||
System.out.println("dv sq " + res);
|
||||
return (pref.signum() >= 0) ? Math.sqrt(res) : -Math.sqrt(res);
|
||||
} /* NumeroAvanzato.doubleValue */
|
||||
|
||||
/**
|
||||
* Return a float value representation.
|
||||
*
|
||||
* @return The value with single precision.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public float floatValue() {
|
||||
return (float) (doubleValue());
|
||||
} /* NumeroAvanzato.floatValue */
|
||||
|
||||
/**
|
||||
* True if the value is integer. Equivalent to the indication whether a
|
||||
* conversion to an integer can be exact.
|
||||
* @param hasBigIntegerVariables
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public boolean isBigInteger(boolean hasBigIntegerVariables) {
|
||||
if (pref.isBigInteger() && (disc.signum() == 0 || disc.compareTo(Rational.ONE) == 0)) {
|
||||
if (disc.signum() != 0 && incognitex.count() > 0) {
|
||||
return false;
|
||||
}
|
||||
if (hasBigIntegerVariables == false && incognitey.count() > 0) {
|
||||
return false;
|
||||
}
|
||||
if (pref.b.compareTo(BigInteger.ZERO) != 0 && disc.b.compareTo(BigInteger.ZERO) != 0 && incognitez.count() > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} /* NumeroAvanzato.isBigInteger */
|
||||
|
||||
public boolean isRational(boolean hasRationalVariables) {
|
||||
if (disc.signum() == 0 || disc.compareTo(new Rational(1, 1)) == 0) {
|
||||
if (incognitex.count() > 0) {
|
||||
return false;
|
||||
} else if (hasRationalVariables == false) {
|
||||
if (incognitey.count() > 0 || incognitez.count() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pref.b.compareTo(new BigInteger("10000")) > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
} /* NumeroAvanzato.isRational */
|
||||
|
||||
public boolean isTooPreciseRational(boolean hasRationalVariables) {
|
||||
if (disc.signum() == 0 || disc.compareTo(new Rational(1, 1)) == 0) {
|
||||
if (incognitex.count() > 0) {
|
||||
return false;
|
||||
} else if (hasRationalVariables == false) {
|
||||
if (incognitey.count() > 0 || incognitez.count() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pref.b.compareTo(new BigInteger("10000")) > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
} /* NumeroAvanzato.isRational */
|
||||
|
||||
/**
|
||||
* Convert to a rational value if possible
|
||||
* @throws Errore
|
||||
*
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public Rational toRational(boolean hasRationalVariables) throws Errore {
|
||||
if (isRational(hasRationalVariables) || isTooPreciseRational(hasRationalVariables))
|
||||
return pref;
|
||||
else
|
||||
throw new ArithmeticException("Undefined conversion " + toFancyString() + " to Rational.");
|
||||
} /* NumeroAvanzato.toRational */
|
||||
|
||||
public Rational toRational() throws Errore {
|
||||
if (isRational(true))
|
||||
return pref;
|
||||
else
|
||||
throw new ArithmeticException("Undefined conversion " + toFancyString() + " to Rational.");
|
||||
}
|
||||
|
||||
/**
|
||||
* The sign: 1 if the number is >0, 0 if ==0, -1 if <0
|
||||
*
|
||||
* @return the signum of the value.
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public int signum() {
|
||||
/*
|
||||
* Since the disc is kept positive, this is the same as the sign of the
|
||||
* prefactor. This works because a zero discriminant is always copied
|
||||
* over to the prefactor, not hidden.
|
||||
*/
|
||||
return pref.signum();
|
||||
} /* NumeroAvanzato.signum */
|
||||
|
||||
/**
|
||||
* Normalize to squarefree discriminant.
|
||||
* @throws Errore
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
protected void normalize() throws Errore {
|
||||
/*
|
||||
* Move squares out of the numerator and denominator of the discriminant
|
||||
*/
|
||||
if (disc.signum() != 0) {
|
||||
/*
|
||||
* square-free part of the numerator: numer = numC*some^2
|
||||
*/
|
||||
BigInteger numC = BigIntegerMath.core(disc.numer());
|
||||
/*
|
||||
* extract the perfect square of the numerator
|
||||
*/
|
||||
BigInteger sq = disc.numer().divide(numC);
|
||||
/*
|
||||
* extract the associated square root
|
||||
*/
|
||||
BigInteger sqf = BigIntegerMath.isqrt(sq);
|
||||
|
||||
/*
|
||||
* move sqf over to the pre-factor
|
||||
*/
|
||||
pref = pref.multiply(sqf);
|
||||
|
||||
BigInteger denC = BigIntegerMath.core(disc.denom());
|
||||
sq = disc.denom().divide(denC);
|
||||
sqf = BigIntegerMath.isqrt(sq);
|
||||
try {
|
||||
pref = pref.divide(sqf);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
disc = new Rational(numC, denC);
|
||||
|
||||
if (disc.b.compareTo(BigInteger.ZERO) == 0 || disc.a.compareTo(BigInteger.ZERO) == 0 || pref.a.compareTo(BigInteger.ZERO) == 0) {
|
||||
incognitex = new Incognite();
|
||||
incognitey = new Incognite();
|
||||
}
|
||||
|
||||
if (disc.b.compareTo(BigInteger.ZERO) == 0 || pref.b.compareTo(BigInteger.ZERO) == 0) {
|
||||
incognitez = new Incognite();
|
||||
}
|
||||
|
||||
if (incognitey.compareTo(incognitez)) {
|
||||
incognitey = new Incognite();
|
||||
incognitez = new Incognite();
|
||||
}
|
||||
|
||||
/**/
|
||||
Incognite[] incognitetemp = new Incognite[]{incognitex, incognitey, incognitez};
|
||||
incognitetemp = Incognite.normalizeBigSurdVariables(incognitetemp);
|
||||
incognitex = incognitetemp[0];
|
||||
incognitey = incognitetemp[1];
|
||||
incognitez = incognitetemp[2];
|
||||
/**/
|
||||
} else {
|
||||
pref = Rational.ZERO;
|
||||
incognitex = new Incognite();
|
||||
incognitey = new Incognite();
|
||||
incognitez = new Incognite();
|
||||
}
|
||||
} /* NumeroAvanzato.normalize */
|
||||
|
||||
/**
|
||||
* Normalize to coprime numerator and denominator in prefactor and
|
||||
* discriminant
|
||||
* @throws Errore
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
protected void normalizeG() throws Errore {
|
||||
/*
|
||||
* Is there a common factor between the numerator of the prefactor and
|
||||
* the denominator of the discriminant ?
|
||||
*/
|
||||
BigInteger d = pref.numer().abs().gcd(disc.denom());
|
||||
if (d.compareTo(BigInteger.ONE) > 0) {
|
||||
try {
|
||||
pref = pref.divide(d);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
/*
|
||||
* instead of multiplying with the square of d, using two steps
|
||||
* offers a change to recognize the common factor..
|
||||
*/
|
||||
disc = disc.multiply(d);
|
||||
disc = disc.multiply(d);
|
||||
}
|
||||
/*
|
||||
* Is there a common factor between the denominator of the prefactor and
|
||||
* the numerator of the discriminant ?
|
||||
*/
|
||||
d = pref.denom().gcd(disc.numer());
|
||||
if (d.compareTo(BigInteger.ONE) > 0) {
|
||||
pref = pref.multiply(d);
|
||||
/*
|
||||
* instead of dividing through the square of d, using two steps
|
||||
* offers a change to recognize the common factor..
|
||||
*/
|
||||
disc = disc.divide(d);
|
||||
disc = disc.divide(d);
|
||||
}
|
||||
} /* NumeroAvanzato.normalizeG */
|
||||
|
||||
/**
|
||||
* Return the approximate floating point representation.
|
||||
*
|
||||
* @param mc
|
||||
* Description of the accuracy needed.
|
||||
* @return A representation with digits valid as described by mc
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public BigDecimal BigDecimalValue(MathContext mc) {
|
||||
/*
|
||||
* the relative error of the result equals the relative error of the
|
||||
* prefactor plus half of the relative error of the discriminant. So
|
||||
* adding 3 digits temporarily is sufficient.
|
||||
*/
|
||||
final MathContext locmc = new MathContext(mc.getPrecision() + 3, mc.getRoundingMode());
|
||||
/*
|
||||
* first the square root of the discriminant
|
||||
*/
|
||||
BigDecimal sqrdis = BigDecimalMath.sqrt(disc.BigDecimalValue(locmc), locmc);
|
||||
/*
|
||||
* Then multiply by the prefactor. If sqrdis is a terminating decimal
|
||||
* fraction, we prevent early truncation of the result by truncating
|
||||
* later.
|
||||
*/
|
||||
BigDecimal res = sqrdis.multiply(pref.BigDecimalValue(mc));
|
||||
return BigDecimalMath.scalePrec(res, mc);
|
||||
} /* BigDecimalValue */
|
||||
|
||||
@Override
|
||||
public boolean equals(Object val) {
|
||||
if (val instanceof NumeroAvanzato) {
|
||||
NumeroAvanzato na = (NumeroAvanzato) val;
|
||||
try {
|
||||
if (pow2().pref == na.pow2().pref) {
|
||||
if (pow2().pref == Rational.ZERO) {
|
||||
return true;
|
||||
} else {
|
||||
if (incognitex == na.incognitex) {
|
||||
if (incognitey == na.incognitey) {
|
||||
if (incognitez == na.incognitez) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Incognite getIncognitex() {
|
||||
if (incognitex == null) {
|
||||
return incognitex;
|
||||
}
|
||||
return incognitex.clone();
|
||||
}
|
||||
|
||||
public NumeroAvanzato setIncognitex(Incognite incognitex) {
|
||||
NumeroAvanzato result = this.clone();
|
||||
result.incognitex = incognitex;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Incognite getIncognitey() {
|
||||
if (incognitey == null) {
|
||||
return incognitey;
|
||||
}
|
||||
return incognitey.clone();
|
||||
}
|
||||
|
||||
public NumeroAvanzato setIncognitey(Incognite incognitey) {
|
||||
NumeroAvanzato result = this.clone();
|
||||
result.incognitey = incognitey;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Incognite getIncognitez() {
|
||||
if (incognitez == null) {
|
||||
return incognitez;
|
||||
}
|
||||
return incognitez.clone();
|
||||
}
|
||||
|
||||
public NumeroAvanzato setIncognitez(Incognite incognitez) {
|
||||
NumeroAvanzato result = this.clone();
|
||||
result.incognitez = incognitez;
|
||||
return result;
|
||||
}
|
||||
|
||||
public NumeroAvanzato divideUnsafe(BigInteger denominator) {
|
||||
try {
|
||||
return divide(denominator);
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
return new NumeroAvanzato();
|
||||
}
|
||||
}
|
||||
|
||||
} /* NumeroAvanzato */
|
752
src/org/nevec/rjm/NumeroAvanzatoVec.java
Normal file
752
src/org/nevec/rjm/NumeroAvanzatoVec.java
Normal file
@ -0,0 +1,752 @@
|
||||
package org.nevec.rjm;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.MathContext;
|
||||
import java.util.Comparator;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.warpgate.pi.calculator.Errore;
|
||||
import org.warpgate.pi.calculator.Incognita;
|
||||
import org.warpgate.pi.calculator.Incognite;
|
||||
import org.warpgate.pi.calculator.Utils;
|
||||
|
||||
/**
|
||||
* A NumeroAvanzatoVec represents an algebraic sum or differences of values which each
|
||||
* term an instance of NumeroAvanzato. This mainly means that sums or differences of
|
||||
* two NumeroAvanzato (or two NumeroAvanzatoVec) can be represented (exactly) as a NumeroAvanzatoVec.
|
||||
*
|
||||
* @since 2012-02-15
|
||||
* @author Richard J. Mathar
|
||||
*/
|
||||
public class NumeroAvanzatoVec implements Comparable<NumeroAvanzatoVec> {
|
||||
/**
|
||||
* The value of zero.
|
||||
*/
|
||||
public static final NumeroAvanzatoVec ZERO = new NumeroAvanzatoVec();
|
||||
|
||||
/**
|
||||
* The value of one.
|
||||
*/
|
||||
public static final NumeroAvanzatoVec ONE = new NumeroAvanzatoVec(NumeroAvanzato.ONE);
|
||||
|
||||
/**
|
||||
* Internal representation: Each term as a single NumeroAvanzato. The value zero is
|
||||
* represented by an empty vector.
|
||||
*/
|
||||
Vector<NumeroAvanzato> terms;
|
||||
|
||||
/**
|
||||
* Default ctor, which represents the zero.
|
||||
*
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public NumeroAvanzatoVec() {
|
||||
terms = new Vector<NumeroAvanzato>();
|
||||
} /* ctor */
|
||||
|
||||
/**
|
||||
* ctor given the value of a NumeroAvanzato.
|
||||
*
|
||||
* @param a
|
||||
* The value to be represented by this vector.
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public NumeroAvanzatoVec(NumeroAvanzato a) {
|
||||
terms = new Vector<NumeroAvanzato>(1);
|
||||
terms.add(a);
|
||||
} /* ctor */
|
||||
|
||||
/**
|
||||
* ctor given two values, which (when added) represent this number a+b.
|
||||
*
|
||||
* @param a
|
||||
* The value to be represented by the first term of the vector.
|
||||
* @param b
|
||||
* The value to be represented by the second term of the vector.
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public NumeroAvanzatoVec(NumeroAvanzato a, NumeroAvanzato b) {
|
||||
terms = new Vector<NumeroAvanzato>(2);
|
||||
terms.add(a);
|
||||
terms.add(b);
|
||||
try {
|
||||
normalize();
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} /* ctor */
|
||||
|
||||
/**
|
||||
* Combine terms that can be written as a single surd. This unites for
|
||||
* example the terms sqrt(90) and sqrt(10) to 4*sqrt(10).
|
||||
* @throws Errore
|
||||
*
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
protected void normalize() throws Errore {
|
||||
/*
|
||||
* nothing to be done if at most one term
|
||||
*/
|
||||
if (terms.size() <= 1)
|
||||
return;
|
||||
|
||||
Vector<NumeroAvanzato> newter = new Vector<NumeroAvanzato>();
|
||||
newter.add(terms.firstElement());
|
||||
/*
|
||||
* add j-th element to the existing vector and combine were possible
|
||||
*/
|
||||
for (int j = 1; j < terms.size(); j++) {
|
||||
NumeroAvanzato todo = terms.elementAt(j);
|
||||
boolean merged = false;
|
||||
for (int ex = 0; ex < newter.size(); ex++) {
|
||||
NumeroAvanzato v = newter.elementAt(ex);
|
||||
/*
|
||||
* try to merge terms[j] and newter[ex]. todo = r * v with r a
|
||||
* rational number is needed. Replaces v with v+todo = v*(1+r)
|
||||
* if this reduction works.
|
||||
*/
|
||||
NumeroAvanzato r = todo.divide(v);
|
||||
if ((r.isRational(true) || r.isTooPreciseRational(true)) && todo.getIncognitex().compareTo(v.getIncognitex()) && todo.getIncognitey().compareTo(v.getIncognitey()) && todo.getIncognitez().compareTo(v.getIncognitez())) {
|
||||
/* compute r+1 */
|
||||
Rational newpref = r.toRational(true).add(1);
|
||||
/*
|
||||
* eliminate accidental zeros; overwrite with v*(1+r).
|
||||
*/
|
||||
if (newpref.compareTo(Rational.ZERO) == 0)
|
||||
newter.removeElementAt(ex);
|
||||
else {
|
||||
v = v.multiply(newpref);
|
||||
newter.setElementAt(v, ex);
|
||||
}
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* append if none of the existing elements matched
|
||||
*/
|
||||
if (!merged)
|
||||
newter.add(todo);
|
||||
}
|
||||
|
||||
newter.sort(new Comparator<NumeroAvanzato>() {
|
||||
@Override
|
||||
public int compare(NumeroAvanzato o1, NumeroAvanzato o2) {
|
||||
int index1 = Incognite.priorità(o1.getIncognitex().sqrt().multiply(o1.getIncognitey()).divide(o1.getIncognitez()));
|
||||
int index2 = Incognite.priorità(o2.getIncognitex().sqrt().multiply(o2.getIncognitey()).divide(o2.getIncognitez()));
|
||||
return index2-index1;
|
||||
}
|
||||
});
|
||||
|
||||
/* overwrite old version */
|
||||
terms = newter;
|
||||
} /* normalize */
|
||||
|
||||
/**
|
||||
* Compare algebraic value with oth. Returns -1, 0 or +1 depending on
|
||||
* whether this is smaller, equal to or larger than oth.
|
||||
*
|
||||
* @param oth
|
||||
* The value with which this is to be compared.
|
||||
* @return 0 or +-1.
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public int compareTo(NumeroAvanzatoVec oth) {
|
||||
NumeroAvanzatoVec diff;
|
||||
try {
|
||||
diff = this.subtract(oth);
|
||||
return diff.signum();
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
} /* compareTo */
|
||||
|
||||
/**
|
||||
* Sign function. Returns -1, 0 or +1 depending on whether this is smaller,
|
||||
* equal to or larger than zero.
|
||||
*
|
||||
* @return 0 or +-1.
|
||||
* @throws Errore
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public int signum() throws Errore {
|
||||
/*
|
||||
* the case of zero is unique, because no (reduced) vector of surds
|
||||
* other than the one element 0 itself can add/subtract to zero.
|
||||
*/
|
||||
if (terms.size() == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* if there is one term: forward to the signum function of NumeroAvanzato
|
||||
*/
|
||||
if (terms.size() == 1)
|
||||
return terms.firstElement().signum();
|
||||
|
||||
/*
|
||||
* if all terms have a common sign: take that one offsig is the index of
|
||||
* the first "offending" term in the sense that its sign doese not agree
|
||||
* with the term[0].
|
||||
*/
|
||||
int sig0 = terms.elementAt(0).signum();
|
||||
int offsig = 1;
|
||||
for (; offsig < terms.size(); offsig++)
|
||||
if (terms.elementAt(offsig).signum() != sig0)
|
||||
break;
|
||||
if (offsig >= terms.size())
|
||||
return sig0;
|
||||
|
||||
/*
|
||||
* if there are two terms (now known to have different sign): forward to
|
||||
* the comparison of the two elements as NumeroAvanzatos
|
||||
*/
|
||||
if (terms.size() == 2)
|
||||
return terms.elementAt(0).signumComparedTo(terms.elementAt(1).negate());
|
||||
|
||||
/*
|
||||
* if there are three terms, move the one with the offending sign to the
|
||||
* other side and square both sides (which looses the sign) to remove
|
||||
* all but one surds. The difference of the squared sides contains at
|
||||
* most two terms, which reduces to the case above. t(0)+t(offbar) <>
|
||||
* -t(offs)
|
||||
*/
|
||||
if (terms.size() == 3) {
|
||||
NumeroAvanzatoVec lhs;
|
||||
if (offsig == 2)
|
||||
lhs = new NumeroAvanzatoVec(terms.elementAt(0), terms.elementAt(1));
|
||||
else
|
||||
lhs = new NumeroAvanzatoVec(terms.elementAt(0), terms.elementAt(2));
|
||||
lhs = lhs.sqr();
|
||||
/*
|
||||
* Strange line: this line isn't used, but it's present in this code!
|
||||
*
|
||||
*
|
||||
*
|
||||
NumeroAvanzato rhs = new NumeroAvanzato(terms.elementAt(offsig).sqr(), Rational.ONE);
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (lhs.compareTo(lhs) > 0)
|
||||
/*
|
||||
* dominating sign was t(0)+t(offbar)
|
||||
*/
|
||||
return terms.elementAt(0).signum();
|
||||
else
|
||||
return terms.elementAt(offsig).signum();
|
||||
}
|
||||
|
||||
/*
|
||||
* for a larger number of terms: take a floating point representation
|
||||
* with a small but correct number of digits, and resume with the sign
|
||||
* of that one.
|
||||
*/
|
||||
return (floatValue() > 0.) ? 1 : -1;
|
||||
|
||||
} /* signum */
|
||||
|
||||
/**
|
||||
* Construct an approximate floating point representation
|
||||
*
|
||||
* @param mc
|
||||
* The intended accuracy of the result.
|
||||
* @return A truncated version with the precision described by mc
|
||||
*/
|
||||
public BigDecimal BigDecimalValue(MathContext mc) {
|
||||
/*
|
||||
* simple cases with one term forwarded to the NumeroAvanzato class
|
||||
*/
|
||||
if (terms.size() == 0)
|
||||
return BigDecimal.ZERO;
|
||||
else if (terms.size() == 1) {
|
||||
return terms.firstElement().BigDecimalValue(mc);
|
||||
}
|
||||
|
||||
/*
|
||||
* To reduce cancellation errors, loop over increasing local precision
|
||||
* until we are stable to the required result. Keep the old (less
|
||||
* precise) estimate in res[0], and the newer, more precise in res[1].
|
||||
*/
|
||||
BigDecimal[] res = new BigDecimal[2];
|
||||
res[0] = BigDecimal.ZERO;
|
||||
for (int addpr = 1;; addpr += 3) {
|
||||
MathContext locmc = new MathContext(mc.getPrecision() + addpr, mc.getRoundingMode());
|
||||
res[1] = BigDecimal.ZERO;
|
||||
for (NumeroAvanzato j : terms)
|
||||
res[1] = BigDecimalMath.addRound(res[1], j.BigDecimalValue(locmc));
|
||||
if (addpr > 1) {
|
||||
BigDecimal err = res[1].subtract(res[0]).abs();
|
||||
int prec = BigDecimalMath.err2prec(res[1], err);
|
||||
if (prec == Integer.MIN_VALUE) {
|
||||
break;
|
||||
}
|
||||
if (prec > mc.getPrecision())
|
||||
break;
|
||||
}
|
||||
res[0] = res[1];
|
||||
}
|
||||
return BigDecimalMath.scalePrec(res[1], mc);
|
||||
|
||||
} /* BigDecimalValue */
|
||||
|
||||
/**
|
||||
* Construct an approximate floating point representation
|
||||
*
|
||||
* @return A truncated version with the precision described by mc
|
||||
*/
|
||||
public double doubleValue() {
|
||||
BigDecimal bd = BigDecimalValue(MathContext.DECIMAL128);
|
||||
return bd.doubleValue();
|
||||
} /* doubleValue */
|
||||
|
||||
/**
|
||||
* Construct an approximate floating point representation
|
||||
*
|
||||
* @return A truncated version with the precision described by mc
|
||||
*/
|
||||
public double floatValue() {
|
||||
BigDecimal bd = BigDecimalValue(MathContext.DECIMAL64);
|
||||
return bd.floatValue();
|
||||
} /* floatValue */
|
||||
|
||||
/**
|
||||
* Add two vectors algebraically.
|
||||
*
|
||||
* @param val
|
||||
* The value to be added to this.
|
||||
* @return The new value representing this+val.
|
||||
* @throws Errore
|
||||
*/
|
||||
public NumeroAvanzatoVec add(final NumeroAvanzatoVec val) throws Errore {
|
||||
NumeroAvanzatoVec sum = new NumeroAvanzatoVec();
|
||||
/*
|
||||
* concatenate the vectors and eliminate common overlaps
|
||||
*/
|
||||
for (NumeroAvanzato term : terms) {
|
||||
if (term.signumComparedTo(NumeroAvanzato.ZERO) != 0) {
|
||||
sum.terms.add(term);
|
||||
}
|
||||
}
|
||||
for (NumeroAvanzato term : val.terms) {
|
||||
if (term.signumComparedTo(NumeroAvanzato.ZERO) != 0) {
|
||||
sum.terms.add(term);
|
||||
}
|
||||
}
|
||||
sum.normalize();
|
||||
return sum;
|
||||
} /* add */
|
||||
|
||||
/**
|
||||
* Add two vectors algebraically.
|
||||
*
|
||||
* @param val
|
||||
* The value to be added to this.
|
||||
* @return The new value representing this+val.
|
||||
* @throws Errore
|
||||
*/
|
||||
public NumeroAvanzatoVec add(final NumeroAvanzato val) throws Errore {
|
||||
NumeroAvanzatoVec sum = new NumeroAvanzatoVec();
|
||||
/*
|
||||
* concatenate the vectors and eliminate common overlaps
|
||||
*/
|
||||
sum.terms.addAll(terms);
|
||||
sum.terms.add(val);
|
||||
sum.normalize();
|
||||
return sum;
|
||||
} /* add */
|
||||
|
||||
/**
|
||||
* Subtract another number.
|
||||
*
|
||||
* @param val
|
||||
* The value to be subtracted from this.
|
||||
* @return The new value representing this-val.
|
||||
* @throws Errore
|
||||
*/
|
||||
public NumeroAvanzatoVec subtract(final NumeroAvanzatoVec val) throws Errore {
|
||||
NumeroAvanzatoVec sum = new NumeroAvanzatoVec();
|
||||
/*
|
||||
* concatenate the vectors and eliminate common overlaps
|
||||
*/
|
||||
sum.terms.addAll(terms);
|
||||
for (NumeroAvanzato s : val.terms)
|
||||
sum.terms.add(s.negate());
|
||||
sum.normalize();
|
||||
return sum;
|
||||
} /* subtract */
|
||||
|
||||
/**
|
||||
* Subtract another number.
|
||||
*
|
||||
* @param val
|
||||
* The value to be subtracted from this.
|
||||
* @return The new value representing this-val.
|
||||
* @throws Errore
|
||||
*/
|
||||
public NumeroAvanzatoVec subtract(final NumeroAvanzato val) throws Errore {
|
||||
NumeroAvanzatoVec sum = new NumeroAvanzatoVec();
|
||||
/*
|
||||
* concatenate the vectors and eliminate common overlaps
|
||||
*/
|
||||
sum.terms.addAll(terms);
|
||||
sum.terms.add(val.negate());
|
||||
sum.normalize();
|
||||
return sum;
|
||||
} /* subtract */
|
||||
|
||||
/**
|
||||
* Compute the negative.
|
||||
*
|
||||
* @return -this.
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public NumeroAvanzatoVec negate() {
|
||||
/*
|
||||
* accumulate the negated elements of term one by one
|
||||
*/
|
||||
NumeroAvanzatoVec resul = new NumeroAvanzatoVec();
|
||||
for (NumeroAvanzato s : terms)
|
||||
resul.terms.add(s.negate());
|
||||
/*
|
||||
* no normalization step here, because the negation of all terms does
|
||||
* not introduce new common factors
|
||||
*/
|
||||
return resul;
|
||||
} /* negate */
|
||||
|
||||
/**
|
||||
* Compute the square.
|
||||
*
|
||||
* @return this value squared.
|
||||
* @throws Errore
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public NumeroAvanzatoVec sqr() throws Errore {
|
||||
/*
|
||||
* Binomial expansion. First the sum of the terms squared, then 2 times
|
||||
* the mixed products.
|
||||
*/
|
||||
NumeroAvanzatoVec resul = new NumeroAvanzatoVec();
|
||||
for (int i = 0; i < terms.size(); i++)
|
||||
resul.terms.add(terms.elementAt(i).pow2());
|
||||
for (int i = 0; i < terms.size() - 1; i++)
|
||||
for (int j = i + 1; j < terms.size(); j++)
|
||||
resul.terms.add(terms.elementAt(i).multiply(terms.elementAt(j)).multiply(2));
|
||||
resul.normalize();
|
||||
return resul;
|
||||
} /* sqr */
|
||||
|
||||
/**
|
||||
* Multiply by another square root.
|
||||
*
|
||||
* @param val
|
||||
* a second number of this type.
|
||||
* @return the product of this with the val.
|
||||
* @throws Errore
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public NumeroAvanzatoVec multiply(final NumeroAvanzato val) throws Errore {
|
||||
NumeroAvanzatoVec resul = new NumeroAvanzatoVec();
|
||||
for (NumeroAvanzato s : terms)
|
||||
resul.terms.add(s.multiply(val));
|
||||
resul.normalize();
|
||||
return resul;
|
||||
} /* multiply */
|
||||
|
||||
public NumeroAvanzatoVec multiply(final NumeroAvanzatoVec val) throws Errore {
|
||||
NumeroAvanzatoVec resul = new NumeroAvanzatoVec();
|
||||
for (NumeroAvanzato s : terms) {
|
||||
for (NumeroAvanzato s2 : val.terms) {
|
||||
resul = resul.add(s.multiply(s2));
|
||||
}
|
||||
}
|
||||
return resul;
|
||||
} /* multiply */
|
||||
|
||||
public NumeroAvanzatoVec divide(final NumeroAvanzato val) throws Errore {
|
||||
NumeroAvanzatoVec resul = new NumeroAvanzatoVec();
|
||||
for (NumeroAvanzato s : terms) {
|
||||
resul.terms.add(s.divide(val));
|
||||
}
|
||||
resul.normalize();
|
||||
return resul;
|
||||
} /* divide */
|
||||
|
||||
public NumeroAvanzatoVec divide(final NumeroAvanzatoVec val) throws Errore {
|
||||
NumeroAvanzatoVec resul = new NumeroAvanzatoVec();
|
||||
resul.terms = this.terms;
|
||||
for (NumeroAvanzato s : val.terms) {
|
||||
resul = resul.divide(s);
|
||||
}
|
||||
return resul;
|
||||
} /* divide */
|
||||
|
||||
/**
|
||||
* True if the value is rational. Equivalent to the indication whether a
|
||||
* conversion to a Rational can be exact.
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public boolean isRational(boolean hasRationalVariables) {
|
||||
boolean val = false;
|
||||
for (NumeroAvanzato s : terms) {
|
||||
val = s.isRational(hasRationalVariables);
|
||||
if (val == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
} /* NumeroAvanzatoVec.isRational */
|
||||
|
||||
public boolean isNumeroAvanzato() {
|
||||
return (this.terms.size() <= 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the value is BigInteger. Equivalent to the indication whether a
|
||||
* conversion to a BigInteger can be exact.
|
||||
*
|
||||
* @since 2011-02-12
|
||||
*/
|
||||
public boolean isBigInteger(boolean hasBigIntegerVariables) {
|
||||
boolean val = false;
|
||||
for (NumeroAvanzato s : terms) {
|
||||
val = s.isBigInteger(hasBigIntegerVariables);
|
||||
if (val == true) {
|
||||
if (s.getIncognitex().count() > 0 || s.getIncognitez().count() > 0) {
|
||||
val = false;
|
||||
}
|
||||
}
|
||||
if (val == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
} /* NumeroAvanzatoVec.isRational */
|
||||
|
||||
/**
|
||||
* Convert to a rational value if possible
|
||||
*
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public Rational toRational(boolean hasRationalVariables) {
|
||||
Rational rat = Rational.ZERO;
|
||||
if (isRational(hasRationalVariables) == false)
|
||||
throw new ArithmeticException("Undefined conversion " + toString() + " to Rational.");
|
||||
for (NumeroAvanzato s : terms) {
|
||||
rat = rat.add(s.pref);
|
||||
}
|
||||
return rat;
|
||||
} /* NumeroAvanzato.toRational */
|
||||
|
||||
/**
|
||||
* Convert to a BigInteger value if possible
|
||||
*
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public BigInteger toBigInteger(boolean hasBigIntegerVariables) {
|
||||
BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode);
|
||||
if (isBigInteger(hasBigIntegerVariables) == false)
|
||||
throw new ArithmeticException("Undefined conversion " + toString() + " to Rational.");
|
||||
for (NumeroAvanzato s : terms) {
|
||||
tmp = BigDecimalMath.addRound(tmp, s.pref.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)));
|
||||
}
|
||||
return tmp.toBigInteger();
|
||||
} /* NumeroAvanzato.toRational */
|
||||
|
||||
/**
|
||||
* Convert to a BigDecimal value if possible
|
||||
*
|
||||
* @since 2012-02-15
|
||||
*/
|
||||
public BigDecimal toBigDecimal() {
|
||||
BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode);
|
||||
for (NumeroAvanzato s : terms) {
|
||||
tmp = BigDecimalMath.addRound(tmp, s.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)));
|
||||
}
|
||||
return tmp;
|
||||
} /* NumeroAvanzato.toBigDecimal */
|
||||
|
||||
|
||||
public NumeroAvanzato toNumeroAvanzato() {
|
||||
if (this.terms.size() == 0) {
|
||||
return NumeroAvanzato.ZERO;
|
||||
}
|
||||
return this.terms.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string in the format (number/denom)*()^(1/2). If the
|
||||
* discriminant equals 1, print just the prefactor.
|
||||
*
|
||||
* @return the human-readable version in base 10
|
||||
* @since 2012-02-16
|
||||
*/
|
||||
public String toString() {
|
||||
/*
|
||||
* simple cases with one term forwarded to the NumeroAvanzato class
|
||||
*/
|
||||
return toFancyString();
|
||||
/*
|
||||
if (terms.size() == 0)
|
||||
return new String("0");
|
||||
else {
|
||||
String s = new String();
|
||||
for (int t = 0; t < terms.size(); t++) {
|
||||
NumeroAvanzato bs = terms.elementAt(t);
|
||||
if (bs.signum() > 0)
|
||||
s += "+";
|
||||
s += bs.toString();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
*/
|
||||
} /* toString */
|
||||
|
||||
public String toFancyString() {
|
||||
if (terms.size() == 0) {
|
||||
return new String("0");
|
||||
} else if (terms.size() == 1 && terms.elementAt(0).isTooPreciseRational(true)) {
|
||||
String s = "";
|
||||
NumeroAvanzato bs = terms.elementAt(0).clone();
|
||||
String num = bs.BigDecimalValue(new MathContext(Utils.resultScale, Utils.scaleMode2)).toEngineeringString();
|
||||
if (num.contains("E")) {
|
||||
s += "("+num.replace("E+", "*10^")+")";
|
||||
} else {
|
||||
s += num;
|
||||
}
|
||||
s += bs.getIncognitey().toString();
|
||||
return s;
|
||||
} else {
|
||||
BigInteger denominator = BigInteger.ONE;
|
||||
Incognite incognitedenom = new Incognite();
|
||||
for (int i = 0; i < terms.size(); i++) {
|
||||
denominator = BigIntegerMath.lcm(denominator, terms.elementAt(i).pref.b);
|
||||
//denominator = denominator.multiply(terms.elementAt(i).pref.b);
|
||||
Incognite iz = terms.elementAt(i).getIncognitez();
|
||||
incognitedenom = Incognite.lcm(incognitedenom, iz);
|
||||
}
|
||||
String s = "";
|
||||
|
||||
if (denominator.abs().compareTo(new BigInteger("10000")) > 0) {
|
||||
for (int i = 0; i < terms.size(); i++) {
|
||||
NumeroAvanzato bs = terms.elementAt(i).clone();
|
||||
String num = bs.BigDecimalValue(new MathContext(Utils.resultScale, Utils.scaleMode2)).toEngineeringString().replaceAll("\\.0+$", "").replaceAll("\\.0+E", "E");
|
||||
if (num.contains("E")) {
|
||||
if (bs.signum() > 0) {
|
||||
s += "+";
|
||||
}
|
||||
num = num.replace("E+", "*10^")+")";
|
||||
if (num.contains("*10^1)")) {
|
||||
num = num.replace("*10^1)", ")");
|
||||
} else {
|
||||
num = "("+num;
|
||||
}
|
||||
s += num;
|
||||
} else {
|
||||
if (bs.signum() > 0) {
|
||||
s += "+";
|
||||
}
|
||||
s += num;
|
||||
}
|
||||
s += bs.getIncognitey().toString();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
if (denominator.compareTo(BigInteger.ONE) != 0 || incognitedenom.count() > 0) {
|
||||
if (terms.size() == 1 && terms.get(0).multiply(denominator).isBigInteger(true) == false) {
|
||||
s += "(";
|
||||
}
|
||||
}
|
||||
for (int t = 0; t < terms.size(); t++) {
|
||||
NumeroAvanzato bs = terms.elementAt(t).clone();
|
||||
|
||||
bs = bs.setIncognitey(bs.getIncognitey().divide(bs.getIncognitez()));
|
||||
bs = bs.setIncognitey(bs.getIncognitey().multiply(incognitedenom));
|
||||
bs = bs.multiply(denominator);
|
||||
bs = bs.setIncognitez(incognitedenom);
|
||||
|
||||
bs.pref = new Rational(bs.pref.a, BigInteger.ONE);
|
||||
if (bs.signum() > 0 && t > 0)
|
||||
s += "+";
|
||||
if (bs.isBigInteger(true)) {
|
||||
String numb;
|
||||
try {
|
||||
numb = bs.toRational(true).a.toString();
|
||||
} catch (Errore e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
numb = "";
|
||||
}
|
||||
String incognite = bs.getIncognitey().toString();
|
||||
if (((numb.equals("1") || numb.equals("-1")) == false && incognite.length() > 0) || incognite.length() == 0) {
|
||||
s += numb;
|
||||
} else if (numb.equals("-1")) {
|
||||
s += "-";
|
||||
}
|
||||
s +=incognite;
|
||||
} else if (bs.isRational(true) || bs.isTooPreciseRational(true)) {
|
||||
try {
|
||||
s += bs.toRational(true).toString();
|
||||
} catch (Errore e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
s += bs.getIncognitey().toString();
|
||||
} else {
|
||||
BigInteger numerator = bs.pref.numer();
|
||||
if ((numerator.compareTo(BigInteger.ONE) != 0 || bs.getIncognitey().count() > 0) && (bs.disc.compareTo(BigInteger.ONE) != 0 || bs.getIncognitex().count() > 0)) {
|
||||
if (((bs.getIncognitey().count() > 0) || (bs.getIncognitey().count() == 0 && numerator.toString().length() > 0))) {
|
||||
if ((bs.getIncognitey().count() > 0 && (numerator.toString().equals("1") || numerator.toString().equals("-1")) == false) || bs.getIncognitey().count() == 0) {
|
||||
s += numerator.toString();
|
||||
} else if (numerator.toString().equals("-1")) {
|
||||
s += "-";
|
||||
}
|
||||
}
|
||||
//s += "(";
|
||||
}
|
||||
if (bs.disc.isInteger() && bs.getIncognitex().count() == 0) {
|
||||
s += "Ⓐ(";
|
||||
s += bs.disc.toString();
|
||||
s += ")";
|
||||
} else if((bs.disc.toString().equals("1") || bs.disc.toString().equals("-1")) && bs.getIncognitex().count() > 0) {
|
||||
s += "Ⓐ(";
|
||||
if (bs.disc.toString().equals("-1")) {
|
||||
s += "-";
|
||||
}
|
||||
s += bs.getIncognitex().toString();
|
||||
s += ")";
|
||||
} else {
|
||||
s += "Ⓐ("+bs.disc.toString()+bs.getIncognitex().toString()+")";
|
||||
}
|
||||
if ((numerator.compareTo(BigInteger.ONE) != 0 || bs.getIncognitey().count() > 0) && (bs.disc.compareTo(BigInteger.ONE) != 0 || bs.getIncognitex().count() > 0)) {
|
||||
if (((bs.getIncognitey().count() > 0) || (bs.getIncognitey().count() == 0 && numerator.toString().length() > 0))) {
|
||||
s += bs.getIncognitey().toString();
|
||||
}
|
||||
//s += "(";
|
||||
}
|
||||
if ((numerator.compareTo(BigInteger.ONE) != 0 || bs.getIncognitey().count() > 0) && (bs.disc.compareTo(BigInteger.ONE) != 0 || bs.getIncognitex().count() > 0)) {
|
||||
//s += ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (denominator.compareTo(BigInteger.ONE) != 0 || incognitedenom.count() > 0) {
|
||||
if (terms.size() == 1 && terms.get(0).multiply(denominator).isBigInteger(true) == false) {
|
||||
s += ")";
|
||||
}
|
||||
s += "/";
|
||||
if ((incognitedenom.count() > 0 && (denominator.toString().equals("1") || denominator.toString().equals("-1")) == false) || incognitedenom.count() == 0) {
|
||||
s += denominator;
|
||||
} else if (denominator.toString().equals("-1")) {
|
||||
s += "-";
|
||||
}
|
||||
s += incognitedenom.toString();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
} /* NumeroAvanzatoVec */
|
696
src/org/warp/engine/lwjgl/Display.java
Normal file
696
src/org/warp/engine/lwjgl/Display.java
Normal file
@ -0,0 +1,696 @@
|
||||
package org.warp.engine.lwjgl;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWFramebufferSizeCallback;
|
||||
import org.lwjgl.glfw.GLFWKeyCallback;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.glfw.GLFWWindowSizeCallback;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.opengl.GLUtil;
|
||||
import org.lwjgl.stb.STBTTAlignedQuad;
|
||||
import org.lwjgl.stb.STBTTPackContext;
|
||||
import org.lwjgl.stb.STBTTPackedchar;
|
||||
import org.warpgate.pi.calculator.Calculator;
|
||||
import org.warpgate.pi.calculator.Keyboard;
|
||||
import org.warpgate.pi.calculator.Main;
|
||||
import org.warpgate.pi.calculator.Utils;
|
||||
|
||||
import de.matthiasmann.twl.utils.PNGDecoder;
|
||||
import de.matthiasmann.twl.utils.PNGDecoder.Format;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.warp.engine.lwjgl.GLFWUtil.*;
|
||||
import static org.warp.engine.lwjgl.IOUtil.*;
|
||||
import static org.lwjgl.glfw.Callbacks.*;
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL13.*;
|
||||
import static org.lwjgl.opengl.GL30.*;
|
||||
import static org.lwjgl.stb.STBTruetype.*;
|
||||
import static org.lwjgl.system.MemoryUtil.*;
|
||||
import static org.lwjgl.stb.STBImage.*;
|
||||
|
||||
/**
|
||||
* STB Truetype oversampling demo.
|
||||
*
|
||||
* <p>This is a Java port of <a href="https://github.com/nothings/stb/blob/master/tests/oversample/main.c">https://github
|
||||
* .com/nothings/stb/blob/master/tests/oversample/main.c</a>.</p>
|
||||
*/
|
||||
public final class Display {
|
||||
|
||||
private static final int BITMAP_W = 5*128;
|
||||
private static final int BITMAP_H = 9*256;
|
||||
|
||||
private static final float[] scale = {
|
||||
30.0f,
|
||||
15.0f
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
private final STBTTAlignedQuad q = STBTTAlignedQuad.malloc();
|
||||
private final FloatBuffer xb = memAllocFloat(1);
|
||||
private final FloatBuffer yb = memAllocFloat(1);
|
||||
|
||||
private long window;
|
||||
|
||||
// ----
|
||||
|
||||
private int ww = 480;
|
||||
private int wh = 320;
|
||||
|
||||
private int fbw = ww;
|
||||
private int fbh = wh;
|
||||
|
||||
private int font_tex;
|
||||
private int skin_tex;
|
||||
private int skin_w;
|
||||
private int skin_h;
|
||||
private int skin_comp;
|
||||
private ByteBuffer skin;
|
||||
|
||||
private STBTTPackedchar.Buffer chardata;
|
||||
|
||||
private boolean black_on_white;
|
||||
private boolean integer_align;
|
||||
private boolean translating;
|
||||
private boolean rotating;
|
||||
|
||||
private boolean supportsSRGB;
|
||||
private boolean srgb;
|
||||
|
||||
private float rotate_t, translate_t;
|
||||
|
||||
private boolean show_tex;
|
||||
|
||||
private int font = 0;
|
||||
|
||||
private final int maxCharIndex = 9500;
|
||||
private float[] background = new float[]{0f,0f,0f};
|
||||
public boolean loading = true;
|
||||
public String error = null;
|
||||
public String[] errorStackTrace = null;
|
||||
public final int[] glyphsHeight = new int[]{9, 6};
|
||||
public float translation = 0.0f;
|
||||
public boolean translation_top_to_bottom = true;
|
||||
public static float brightness = 1.0f;
|
||||
|
||||
private Screen screen;
|
||||
|
||||
public Display(Screen screen, int ww, int wh) {
|
||||
this.ww = ww;
|
||||
this.wh = wh;
|
||||
setScreen(screen);
|
||||
}
|
||||
/*
|
||||
private void load_skin() {
|
||||
try {
|
||||
skin_tex = glGenTextures();
|
||||
glBindTexture(GL_TEXTURE_2D, skin_tex);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
InputStream in = new FileInputStream("res/skin.png");
|
||||
PNGDecoder decoder = new PNGDecoder(in);
|
||||
|
||||
System.out.println("width="+decoder.getWidth());
|
||||
System.out.println("height="+decoder.getHeight());
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocateDirect(4*decoder.getWidth()*decoder.getHeight());
|
||||
decoder.decode(buf, decoder.getWidth()*4, Format.RGBA);
|
||||
buf.flip();
|
||||
|
||||
skin = buf;
|
||||
skin_w = decoder.getWidth();
|
||||
skin_h = decoder.getHeight();
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin_w,
|
||||
skin_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, skin);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
private void setScreen(Screen screen) {
|
||||
if (screen.initialized == false) {
|
||||
if (screen.canBeInHistory) {
|
||||
Calculator.currentSession = 0;
|
||||
for (int i = 1; i < Calculator.sessions.length; i++) {
|
||||
Calculator.sessions[i] = Calculator.sessions[i-1];
|
||||
}
|
||||
Calculator.sessions[0] = this.screen;
|
||||
}
|
||||
}
|
||||
screen.d = this;
|
||||
try {
|
||||
screen.initialize();
|
||||
this.screen = screen;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canGoBack() {
|
||||
if (this.screen != Calculator.sessions[Calculator.currentSession]) {
|
||||
|
||||
} else if (Calculator.currentSession+1 < Calculator.sessions.length) {
|
||||
if (Calculator.sessions[Calculator.currentSession + 1] != null) {
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (Calculator.sessions[Calculator.currentSession] != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void goBack() {
|
||||
if (canGoBack()) {
|
||||
if (this.screen != Calculator.sessions[Calculator.currentSession]) {
|
||||
|
||||
} else {
|
||||
Calculator.currentSession += 1;
|
||||
}
|
||||
this.screen = Calculator.sessions[Calculator.currentSession];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean canGoForward() {
|
||||
if (this.screen != Calculator.sessions[Calculator.currentSession]) {
|
||||
|
||||
} else if (Calculator.currentSession > 0) {
|
||||
if (Calculator.sessions[Calculator.currentSession - 1] != null) {
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (Calculator.sessions[Calculator.currentSession] != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void goForward() {
|
||||
if (canGoForward()) {
|
||||
if (this.screen != Calculator.sessions[Calculator.currentSession]) {
|
||||
|
||||
} else {
|
||||
Calculator.currentSession -= 1;
|
||||
}
|
||||
this.screen = Calculator.sessions[Calculator.currentSession];
|
||||
}
|
||||
}
|
||||
|
||||
private Screen getScreen() {
|
||||
return this.screen;
|
||||
}
|
||||
|
||||
|
||||
private void load_skin() {
|
||||
ByteBuffer imageBuffer;
|
||||
try {
|
||||
imageBuffer = ioResourceToByteBuffer("skin.png", 8 * 1024);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
skin_tex = glGenTextures();
|
||||
glBindTexture(GL_TEXTURE_2D, skin_tex);
|
||||
IntBuffer w = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer h = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer comp = BufferUtils.createIntBuffer(1);
|
||||
|
||||
skin = stbi_load_from_memory(imageBuffer, w, h, comp, 0);
|
||||
|
||||
if ( skin == null )
|
||||
throw new RuntimeException("Failed to load image: " + stbi_failure_reason());
|
||||
skin_w = w.get(0);
|
||||
skin_h = h.get(0);
|
||||
skin_comp = comp.get(0);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
if ( skin_comp == 3 ) {
|
||||
if ( (skin_w & 3) != 0 )
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 2 - (skin_w & 1));
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, skin_w, skin_h, 0, GL_RGB, GL_UNSIGNED_BYTE, skin);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin_w, skin_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, skin);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
stbi_image_free(skin);
|
||||
}
|
||||
|
||||
private void load_fonts() {
|
||||
font_tex = glGenTextures();
|
||||
chardata = STBTTPackedchar.mallocBuffer(6*maxCharIndex);
|
||||
glBindTexture(GL_TEXTURE_2D, font_tex);
|
||||
|
||||
|
||||
try {
|
||||
STBTTPackContext pc = STBTTPackContext.malloc();
|
||||
ByteBuffer ttfBig = ioResourceToByteBuffer("font_big.ttf", 18000);
|
||||
ByteBuffer ttfSmall = ioResourceToByteBuffer("font_small.ttf", 18000);
|
||||
|
||||
ByteBuffer bitmap = BufferUtils.createByteBuffer(BITMAP_W * BITMAP_H);
|
||||
|
||||
stbtt_PackBegin(pc, bitmap, BITMAP_W, BITMAP_H, 0, 1, null);
|
||||
chardata.limit(maxCharIndex);
|
||||
chardata.position(0);
|
||||
stbtt_PackSetOversampling(pc, 1, 1);
|
||||
stbtt_PackFontRange(pc, ttfBig, 0, 15 /* Font size */, 0, chardata);
|
||||
chardata.clear();
|
||||
chardata.limit(maxCharIndex*2);
|
||||
chardata.position(maxCharIndex);
|
||||
stbtt_PackSetOversampling(pc, 1, 1);
|
||||
stbtt_PackFontRange(pc, ttfSmall, 0, 15 /* Font size */, 0, chardata);
|
||||
chardata.clear();
|
||||
stbtt_PackEnd(pc);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, BITMAP_W, BITMAP_H, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void draw_init() {
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glViewport(0, 0, fbw, fbh);
|
||||
clearColor(background[0], background[1], background[2], 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, ww, wh, 0.0, -1.0, 1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
private static void drawBoxTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1) {
|
||||
glTexCoord2f(s0, t0);
|
||||
glVertex2f(x0, y0);
|
||||
glTexCoord2f(s1, t0);
|
||||
glVertex2f(x1, y0);
|
||||
glTexCoord2f(s1, t1);
|
||||
glVertex2f(x1, y1);
|
||||
glTexCoord2f(s0, t1);
|
||||
glVertex2f(x0, y1);
|
||||
}
|
||||
|
||||
private void print(float x, float y, int font, String text) {
|
||||
xb.put(0, x);
|
||||
yb.put(0, y+glyphsHeight[font]);
|
||||
|
||||
chardata.position(font * maxCharIndex);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, font_tex);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for ( int i = 0; i < text.length(); i++ ) {
|
||||
stbtt_GetPackedQuad(chardata, BITMAP_W, BITMAP_H, text.charAt(i), xb, yb, q, (font == 0 && integer_align)?1:0);
|
||||
drawBoxTC(
|
||||
q.x0(), q.y0(), q.x1(), q.y1(),
|
||||
q.s0(), q.t0(), q.s1(), q.t1()
|
||||
);
|
||||
}
|
||||
glEnd();
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
}
|
||||
|
||||
private int[] textSize(int font, String text) {
|
||||
float[] size = new float[]{0,0};
|
||||
xb.put(0, 0);
|
||||
yb.put(0, 0);
|
||||
|
||||
chardata.position(font * maxCharIndex);
|
||||
|
||||
for ( int i = 0; i < text.length(); i++ ) {
|
||||
stbtt_GetPackedQuad(chardata, BITMAP_W, BITMAP_H, text.charAt(i), xb, yb, q, (font == 0 && integer_align)?1:0);
|
||||
size[0]=q.x1();
|
||||
size[1]=q.y1();
|
||||
}
|
||||
return new int[]{(int) size[0], (int) size[1]};
|
||||
}
|
||||
|
||||
private void drawSkinPart(int[] posOnScreen, float[] posOnSkin) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
colore(1, 1, 1, 1);
|
||||
glBindTexture(GL_TEXTURE_2D, skin_tex);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
drawBoxTC(posOnScreen[0],posOnScreen[1],posOnScreen[2], posOnScreen[3], posOnSkin[0]/1000, posOnSkin[1]/100, posOnSkin[2]/1000, posOnSkin[3]/100);
|
||||
glEnd();
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
}
|
||||
|
||||
private void drawLine(int[]... pos) {
|
||||
glLineWidth(1.0f);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
||||
for (int[] single_pos : pos) {
|
||||
glVertex2d(single_pos[0], single_pos[1]);
|
||||
glVertex2d(single_pos[2], single_pos[3]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
private void drawRect(int[]... pos) {
|
||||
glLineWidth(1.0f);
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for (int[] single_pos : pos) {
|
||||
glVertex2d(single_pos[0], single_pos[1]);
|
||||
glVertex2d(single_pos[2], single_pos[1]);
|
||||
glVertex2d(single_pos[2], single_pos[3]);
|
||||
glVertex2d(single_pos[0], single_pos[3]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
private void draw_status() {
|
||||
colore(background[0],background[1],background[2]);
|
||||
drawRect(new int[]{0,0,ww,20});
|
||||
colore(0,0,0);
|
||||
drawLine(new int[]{0,20,ww,20});
|
||||
colore(0,0,0);
|
||||
if (Keyboard.shift) {
|
||||
drawSkinPart(new int[]{2+18*0,2,2+16+18*0,2+16}, new float[]{16*2,16*0,16+16*2,16+16*0});
|
||||
} else {
|
||||
drawSkinPart(new int[]{2+18*0,2,2+16+18*0,2+16}, new float[]{16*3,16*0,16+16*3,16+16*0});
|
||||
}
|
||||
if (Keyboard.alpha) {
|
||||
drawSkinPart(new int[]{2+18*1,2,2+16+18*1,2+16}, new float[]{16*0,16*0,16+16*0,16+16*0});
|
||||
} else {
|
||||
drawSkinPart(new int[]{2+18*1,2,2+16+18*1,2+16}, new float[]{16*1,16*0,16+16*1,16+16*0});
|
||||
}
|
||||
if (Calculator.angleMode == "deg") {
|
||||
drawSkinPart(new int[]{8+18*2,2,8+16+18*2,2+16}, new float[]{16*4,16*0,16+16*4,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*3,2,8+16+18*3,2+16}, new float[]{16*7,16*0,16+16*7,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*4,2,8+16+18*4,2+16}, new float[]{16*9,16*0,16+16*9,16+16*0});
|
||||
} else if (Calculator.angleMode == "rad") {
|
||||
drawSkinPart(new int[]{8+18*2,2,8+16+18*2,2+16}, new float[]{16*5,16*0,16+16*5,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*3,2,8+16+18*3,2+16}, new float[]{16*6,16*0,16+16*6,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*4,2,8+16+18*4,2+16}, new float[]{16*9,16*0,16+16*9,16+16*0});
|
||||
} else if (Calculator.angleMode == "gra") {
|
||||
drawSkinPart(new int[]{8+18*2,2,8+16+18*2,2+16}, new float[]{16*5,16*0,16+16*5,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*3,2,8+16+18*3,2+16}, new float[]{16*7,16*0,16+16*7,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*4,2,8+16+18*4,2+16}, new float[]{16*8,16*0,16+16*8,16+16*0});
|
||||
} else {
|
||||
drawSkinPart(new int[]{8+18*2,2,8+16+18*2,2+16}, new float[]{16*5,16*0,16+16*5,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*3,2,8+16+18*3,2+16}, new float[]{16*7,16*0,16+16*7,16+16*0});
|
||||
drawSkinPart(new int[]{8+18*4,2,8+16+18*4,2+16}, new float[]{16*9,16*0,16+16*9,16+16*0});
|
||||
}
|
||||
|
||||
int padding = 2;
|
||||
|
||||
int brightness = (int)(Display.brightness * 4);
|
||||
if (brightness == 1) {
|
||||
drawSkinPart(new int[]{ww-(padding+18*0),2,ww-(padding+16+18*0),2+16}, new float[]{16*10,16*0,16+16*10,16+16*0});
|
||||
} else if (brightness == 2) {
|
||||
drawSkinPart(new int[]{ww-(padding+18*0),2,ww-(padding+16+18*0),2+16}, new float[]{16*11,16*0,16+16*11,16+16*0});
|
||||
} else if (brightness == 3) {
|
||||
drawSkinPart(new int[]{ww-(padding+18*0),2,ww-(padding+16+18*0),2+16}, new float[]{16*12,16*0,16+16*12,16+16*0});
|
||||
} else if (brightness == 4) {
|
||||
drawSkinPart(new int[]{ww-(padding+18*0),2,ww-(padding+16+18*0),2+16}, new float[]{16*13,16*0,16+16*13,16+16*0});
|
||||
}
|
||||
|
||||
padding += 18+6;
|
||||
|
||||
boolean canGoBack = canGoBack();
|
||||
boolean canGoForward = canGoForward();
|
||||
|
||||
|
||||
if (Calculator.haxMode) {
|
||||
drawSkinPart(new int[]{ww-(padding+16),2,ww-padding,2+16}, new float[]{16*18,16*0,16+16*18,16+16*0});
|
||||
padding += 18+6;
|
||||
}
|
||||
|
||||
if (canGoBack && canGoForward) {
|
||||
drawSkinPart(new int[]{ww-(padding+16),2,ww-padding,2+16}, new float[]{16*14,16*0,16+16*14,16+16*0});
|
||||
} else if (canGoBack) {
|
||||
drawSkinPart(new int[]{ww-(padding+16),2,ww-padding,2+16}, new float[]{16*15,16*0,16+16*15,16+16*0});
|
||||
} else if (canGoForward) {
|
||||
drawSkinPart(new int[]{ww-(padding+16),2,ww-padding,2+16}, new float[]{16*16,16*0,16+16*16,16+16*0});
|
||||
} else {
|
||||
drawSkinPart(new int[]{ww-(padding+16),2,ww-padding,2+16}, new float[]{16*17,16*0,16+16*17,16+16*0});
|
||||
}
|
||||
|
||||
padding += 18;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void draw_screen() {
|
||||
screen.render();
|
||||
}
|
||||
|
||||
|
||||
private void draw_bottom() {
|
||||
|
||||
}
|
||||
|
||||
private void draw_world() {
|
||||
float x = 20;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
colore(1.0f, 1.0f, 1.0f);
|
||||
|
||||
if (error != null) {
|
||||
colore(0.0f, 0.0f, 0.0f, 0.75f);
|
||||
print(ww-textSize(1, "ANDREA CAVALLI'S CALCULATOR")[0]-2, wh-this.glyphsHeight[1]-2, 1, "ANDREA CAVALLI'S CALCULATOR");
|
||||
colore(0.0f, 0.0f, 0.0f, 0.75f);
|
||||
print((ww/2)-(textSize(0, "UNEXPECTED EXCEPTION")[0]/2), 11, 0, "UNEXPECTED EXCEPTION");
|
||||
colore(0.0f, 0.0f, 0.0f, 0.5f);
|
||||
print((ww/2)-(textSize(1, error)[0]/2), 22, 1, error);
|
||||
colore(0.0f, 0.0f, 0.0f, 0.4f);
|
||||
int i = 22;
|
||||
for (String stackPart : errorStackTrace) {
|
||||
print(2, 22+i, 1, stackPart);
|
||||
i+=11;
|
||||
}
|
||||
} else if (loading) {
|
||||
colore(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
int titlew = textSize(0, "ANDREA CAVALLI'S CALCULATOR")[0];
|
||||
print((ww/2)-(titlew/2)-1, (wh/2)-25+translation, 0, "ANDREA CAVALLI'S CALCULATOR");
|
||||
colore(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
print((ww/2)-(titlew/2)+1, (wh/2)-25+translation, 0, "ANDREA CAVALLI'S CALCULATOR");
|
||||
colore(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
print((ww/2)-(titlew/2), (wh/2)-25-1+translation, 0, "ANDREA CAVALLI'S CALCULATOR");
|
||||
colore(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
print((ww/2)-(titlew/2), (wh/2)-25+1+translation, 0, "ANDREA CAVALLI'S CALCULATOR");
|
||||
colore(1.0f, 0.5f, 0.0f, 1.0f);
|
||||
print((ww/2)-(titlew/2), (wh/2)-25+translation, 0, "ANDREA CAVALLI'S CALCULATOR");
|
||||
colore(0.0f, 0.0f, 0.0f, 0.75f);
|
||||
print((ww/2)-(textSize(0, "LOADING")[0]/2), (wh/2)+11, 0, "LOADING");
|
||||
colore(0.0f, 0.0f, 0.0f, 0.5f);
|
||||
print((ww/2)-(textSize(1, "PLEASE WAIT...")[0]/2), (wh/2)+22, 1, "PLEASE WAIT...");
|
||||
} else {
|
||||
draw_status();
|
||||
draw_screen();
|
||||
draw_bottom();
|
||||
}
|
||||
}
|
||||
|
||||
private void draw() {
|
||||
draw_init();
|
||||
draw_world();
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
private void loopmode(float dt) {
|
||||
|
||||
rotate_t += dt;
|
||||
translate_t += dt;
|
||||
|
||||
/*
|
||||
* Calcoli
|
||||
*/
|
||||
|
||||
if (translation >= 10.0f) {
|
||||
translation = 10.0f;
|
||||
translation_top_to_bottom = false;
|
||||
} else if (translation <= -10.0f) {
|
||||
translation = -10.0f;
|
||||
translation_top_to_bottom = true;
|
||||
}
|
||||
|
||||
if (translation_top_to_bottom) {
|
||||
translation += dt*15;
|
||||
} else {
|
||||
translation -= dt*15;
|
||||
}
|
||||
|
||||
screen.beforeRender(dt);
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
private GLFWKeyCallback keyCallback = new GLFWKeyCallback() {
|
||||
@Override
|
||||
public void invoke(long window, int key, int scancode, int action, int mods) {
|
||||
if ( action == GLFW_RELEASE )
|
||||
return;
|
||||
switch ( key ) {
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
break;
|
||||
case GLFW_KEY_F:
|
||||
font = 1;
|
||||
break;
|
||||
case GLFW_KEY_R:
|
||||
rotating = !rotating;
|
||||
rotate_t = 0.0f;
|
||||
break;
|
||||
case GLFW_KEY_P:
|
||||
integer_align = !integer_align;
|
||||
break;
|
||||
case GLFW_KEY_G:
|
||||
font = 0;
|
||||
break;
|
||||
case GLFW_KEY_V:
|
||||
show_tex = !show_tex;
|
||||
break;
|
||||
case GLFW_KEY_B:
|
||||
black_on_white = !black_on_white;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private GLFWWindowSizeCallback sizecallback = new GLFWWindowSizeCallback() {
|
||||
@Override
|
||||
public void invoke(long window, int width, int height) {
|
||||
Display.this.ww = width;
|
||||
Display.this.wh = height;
|
||||
}
|
||||
};
|
||||
|
||||
private GLFWFramebufferSizeCallback fbsizecallback = new GLFWFramebufferSizeCallback() {
|
||||
@Override
|
||||
public void invoke(long window, int width, int height) {
|
||||
Display.this.fbw = width;
|
||||
Display.this.fbh = height;
|
||||
}
|
||||
};
|
||||
|
||||
private void createWindow(String title) {
|
||||
GLFWErrorCallback.createPrint().set();
|
||||
if ( glfwInit() == GLFW_FALSE )
|
||||
throw new IllegalStateException("Unable to initialize GLFW");
|
||||
|
||||
glfwDefaultWindowHints();
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
|
||||
this.window = glfwCreateWindow(ww, wh, title, NULL, NULL);
|
||||
if ( window == NULL )
|
||||
throw new RuntimeException("Failed to create the GLFW window");
|
||||
|
||||
glfwSetWindowSizeCallback(window, sizecallback);
|
||||
glfwSetFramebufferSizeCallback(window, fbsizecallback);
|
||||
glfwSetKeyCallback(window, keyCallback);
|
||||
|
||||
// Center window
|
||||
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
|
||||
glfwSetWindowPos(
|
||||
window,
|
||||
(vidmode.width() - ww) / 2,
|
||||
(vidmode.height() - wh) / 2
|
||||
);
|
||||
|
||||
// Create context
|
||||
glfwMakeContextCurrent(window);
|
||||
GL.createCapabilities();
|
||||
|
||||
glfwSwapInterval(1);
|
||||
glfwShowWindow(window);
|
||||
|
||||
glfwInvoke(window, sizecallback, fbsizecallback);
|
||||
|
||||
// Detect sRGB support
|
||||
GLCapabilities caps = GL.getCapabilities();
|
||||
supportsSRGB = caps.OpenGL30 || caps.GL_ARB_framebuffer_sRGB || caps.GL_EXT_framebuffer_sRGB;
|
||||
}
|
||||
|
||||
public void run(String title) {
|
||||
try {
|
||||
createWindow(title);
|
||||
load_skin();
|
||||
load_fonts();
|
||||
|
||||
long time = System.nanoTime();
|
||||
while ( glfwWindowShouldClose(window) == GLFW_FALSE ) {
|
||||
glfwPollEvents();
|
||||
|
||||
long t = System.nanoTime();
|
||||
float dt = (float)((t - time) / 1000000000.0);
|
||||
time = t;
|
||||
|
||||
loopmode(dt);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
destroy();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
chardata.clear();
|
||||
|
||||
glfwTerminate();
|
||||
glfwSetErrorCallback(null);
|
||||
|
||||
memFree(yb);
|
||||
memFree(xb);
|
||||
|
||||
q.free();
|
||||
}
|
||||
|
||||
public void setBackground(float d, float e, float f) {
|
||||
background = new float[]{d,e,f};
|
||||
}
|
||||
|
||||
public void colore(float f1, float f2, float f3) {
|
||||
glColor3f(f1*brightness, f2*brightness, f3*brightness);
|
||||
}
|
||||
|
||||
public void colore(float f1, float f2, float f3, float f4) {
|
||||
glColor4f(f1*brightness, f2*brightness, f3*brightness, f4);
|
||||
}
|
||||
|
||||
public void clearColor(float f1, float f2, float f3, float f4) {
|
||||
glClearColor(f1*brightness,f2*brightness,f3*brightness,f4);
|
||||
}
|
||||
}
|
47
src/org/warp/engine/lwjgl/GLFWUtil.java
Normal file
47
src/org/warp/engine/lwjgl/GLFWUtil.java
Normal file
@ -0,0 +1,47 @@
|
||||
package org.warp.engine.lwjgl;
|
||||
|
||||
import org.lwjgl.glfw.GLFWFramebufferSizeCallbackI;
|
||||
import org.lwjgl.glfw.GLFWWindowSizeCallbackI;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.system.MemoryStack.*;
|
||||
|
||||
/** GLFW demo utilities. */
|
||||
public final class GLFWUtil {
|
||||
|
||||
private GLFWUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the specified callbacks using the current window and framebuffer sizes of the specified GLFW window.
|
||||
*
|
||||
* @param window the GLFW window
|
||||
* @param windowSizeCB the window size callback, may be null
|
||||
* @param framebufferSizeCB the framebuffer size callback, may be null
|
||||
*/
|
||||
public static void glfwInvoke(
|
||||
long window,
|
||||
GLFWWindowSizeCallbackI windowSizeCB,
|
||||
GLFWFramebufferSizeCallbackI framebufferSizeCB
|
||||
) {
|
||||
try ( MemoryStack stack = stackPush() ) {
|
||||
IntBuffer w = stack.mallocInt(1);
|
||||
IntBuffer h = stack.mallocInt(1);
|
||||
|
||||
if ( windowSizeCB != null ) {
|
||||
glfwGetWindowSize(window, w, h);
|
||||
windowSizeCB.invoke(window, w.get(0), h.get(0));
|
||||
}
|
||||
|
||||
if ( framebufferSizeCB != null ) {
|
||||
glfwGetFramebufferSize(window, w, h);
|
||||
framebufferSizeCB.invoke(window, w.get(0), h.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
69
src/org/warp/engine/lwjgl/IOUtil.java
Normal file
69
src/org/warp/engine/lwjgl/IOUtil.java
Normal file
@ -0,0 +1,69 @@
|
||||
package org.warp.engine.lwjgl;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.lwjgl.BufferUtils.*;
|
||||
|
||||
public final class IOUtil {
|
||||
|
||||
private IOUtil() {
|
||||
}
|
||||
|
||||
private static ByteBuffer resizeBuffer(ByteBuffer buffer, int newCapacity) {
|
||||
ByteBuffer newBuffer = BufferUtils.createByteBuffer(newCapacity);
|
||||
buffer.flip();
|
||||
newBuffer.put(buffer);
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the specified resource and returns the raw data as a ByteBuffer.
|
||||
*
|
||||
* @param resource the resource to read
|
||||
* @param bufferSize the initial buffer size
|
||||
*
|
||||
* @return the resource data
|
||||
*
|
||||
* @throws IOException if an IO error occurs
|
||||
*/
|
||||
public static ByteBuffer ioResourceToByteBuffer(String resource, int bufferSize) throws IOException {
|
||||
ByteBuffer buffer;
|
||||
|
||||
Path path = Paths.get(resource);
|
||||
if ( Files.isReadable(path) ) {
|
||||
try (SeekableByteChannel fc = Files.newByteChannel(path)) {
|
||||
buffer = BufferUtils.createByteBuffer((int)fc.size() + 1);
|
||||
while ( fc.read(buffer) != -1 ) ;
|
||||
}
|
||||
} else {
|
||||
try (
|
||||
InputStream source = IOUtil.class.getClassLoader().getResourceAsStream(resource);
|
||||
ReadableByteChannel rbc = Channels.newChannel(source)
|
||||
) {
|
||||
buffer = createByteBuffer(bufferSize);
|
||||
|
||||
while ( true ) {
|
||||
int bytes = rbc.read(buffer);
|
||||
if ( bytes == -1 )
|
||||
break;
|
||||
if ( buffer.remaining() == 0 )
|
||||
buffer = resizeBuffer(buffer, buffer.capacity() * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
23
src/org/warp/engine/lwjgl/Screen.java
Normal file
23
src/org/warp/engine/lwjgl/Screen.java
Normal file
@ -0,0 +1,23 @@
|
||||
package org.warp.engine.lwjgl;
|
||||
|
||||
public abstract class Screen {
|
||||
public Display d;
|
||||
public boolean initialized = false;
|
||||
public boolean canBeInHistory = false;
|
||||
|
||||
public Screen() {
|
||||
}
|
||||
|
||||
public void initialize() throws InterruptedException {
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void init() throws InterruptedException;
|
||||
|
||||
public abstract void render();
|
||||
|
||||
public abstract void beforeRender(float dt);
|
||||
}
|
212
src/org/warpgate/pi/calculator/BMPFile.java
Normal file
212
src/org/warpgate/pi/calculator/BMPFile.java
Normal file
@ -0,0 +1,212 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.awt.image.*;
|
||||
public class BMPFile extends Component {
|
||||
//--- Private constants
|
||||
private final static int BITMAPFILEHEADER_SIZE = 14;
|
||||
private final static int BITMAPINFOHEADER_SIZE = 40;
|
||||
//--- Private variable declaration
|
||||
//--- Bitmap file header
|
||||
private byte bitmapFileHeader [] = new byte [14];
|
||||
private byte bfType [] = {'B', 'M'};
|
||||
private int bfSize = 0;
|
||||
private int bfReserved1 = 0;
|
||||
private int bfReserved2 = 0;
|
||||
private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;
|
||||
//--- Bitmap info header
|
||||
private byte bitmapInfoHeader [] = new byte [40];
|
||||
private int biSize = BITMAPINFOHEADER_SIZE;
|
||||
private int biWidth = 0;
|
||||
private int biHeight = 0;
|
||||
private int biPlanes = 1;
|
||||
private int biBitCount = 24;
|
||||
private int biCompression = 0;
|
||||
private int biSizeImage = 0x030000;
|
||||
private int biXPelsPerMeter = 0x0;
|
||||
private int biYPelsPerMeter = 0x0;
|
||||
private int biClrUsed = 0;
|
||||
private int biClrImportant = 0;
|
||||
//--- Bitmap raw data
|
||||
private int bitmap [];
|
||||
//--- File section
|
||||
private FileOutputStream fo;
|
||||
//--- Default constructor
|
||||
public BMPFile() {
|
||||
}
|
||||
public void saveBitmap (String parFilename, Image parImage, int
|
||||
parWidth, int parHeight) {
|
||||
try {
|
||||
fo = new FileOutputStream (parFilename);
|
||||
save (parImage, parWidth, parHeight);
|
||||
fo.close ();
|
||||
}
|
||||
catch (Exception saveEx) {
|
||||
saveEx.printStackTrace ();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The saveMethod is the main method of the process. This method
|
||||
* will call the convertImage method to convert the memory image to
|
||||
* a byte array; method writeBitmapFileHeader creates and writes
|
||||
* the bitmap file header; writeBitmapInfoHeader creates the
|
||||
* information header; and writeBitmap writes the image.
|
||||
*
|
||||
*/
|
||||
private void save (Image parImage, int parWidth, int parHeight) {
|
||||
try {
|
||||
convertImage (parImage, parWidth, parHeight);
|
||||
writeBitmapFileHeader ();
|
||||
writeBitmapInfoHeader ();
|
||||
writeBitmap ();
|
||||
}
|
||||
catch (Exception saveEx) {
|
||||
saveEx.printStackTrace ();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* convertImage converts the memory image to the bitmap format (BRG).
|
||||
* It also computes some information for the bitmap info header.
|
||||
*
|
||||
*/
|
||||
private boolean convertImage (Image parImage, int parWidth, int parHeight) {
|
||||
int pad;
|
||||
bitmap = new int [parWidth * parHeight];
|
||||
PixelGrabber pg = new PixelGrabber (parImage, 0, 0, parWidth, parHeight,
|
||||
bitmap, 0, parWidth);
|
||||
try {
|
||||
pg.grabPixels ();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace ();
|
||||
return (false);
|
||||
}
|
||||
pad = (4 - ((parWidth * 3) % 4)) * parHeight;
|
||||
biSizeImage = ((parWidth * parHeight) * 3) + pad;
|
||||
bfSize = biSizeImage + BITMAPFILEHEADER_SIZE +
|
||||
BITMAPINFOHEADER_SIZE;
|
||||
biWidth = parWidth;
|
||||
biHeight = parHeight;
|
||||
return (true);
|
||||
}
|
||||
/*
|
||||
* writeBitmap converts the image returned from the pixel grabber to
|
||||
* the format required. Remember: scan lines are inverted in
|
||||
* a bitmap file!
|
||||
*
|
||||
* Each scan line must be padded to an even 4-byte boundary.
|
||||
*/
|
||||
private void writeBitmap () {
|
||||
int size;
|
||||
int value;
|
||||
int j;
|
||||
int i;
|
||||
int rowCount;
|
||||
int rowIndex;
|
||||
int lastRowIndex;
|
||||
int pad;
|
||||
int padCount;
|
||||
byte rgb [] = new byte [3];
|
||||
size = (biWidth * biHeight) - 1;
|
||||
pad = 4 - ((biWidth * 3) % 4);
|
||||
if (pad == 4) // <==== Bug correction
|
||||
pad = 0; // <==== Bug correction
|
||||
rowCount = 1;
|
||||
padCount = 0;
|
||||
rowIndex = size - biWidth;
|
||||
lastRowIndex = rowIndex;
|
||||
try {
|
||||
for (j = 0; j < size; j++) {
|
||||
value = bitmap [rowIndex];
|
||||
rgb [0] = (byte) (value & 0xFF);
|
||||
rgb [1] = (byte) ((value >> 8) & 0xFF);
|
||||
rgb [2] = (byte) ((value >> 16) & 0xFF);
|
||||
fo.write (rgb);
|
||||
if (rowCount == biWidth) {
|
||||
padCount += pad;
|
||||
for (i = 1; i <= pad; i++) {
|
||||
fo.write (0x00);
|
||||
}
|
||||
rowCount = 1;
|
||||
rowIndex = lastRowIndex - biWidth;
|
||||
lastRowIndex = rowIndex;
|
||||
}
|
||||
else
|
||||
rowCount++;
|
||||
rowIndex++;
|
||||
}
|
||||
//--- Update the size of the file
|
||||
bfSize += padCount - pad;
|
||||
biSizeImage += padCount - pad;
|
||||
}
|
||||
catch (Exception wb) {
|
||||
wb.printStackTrace ();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* writeBitmapFileHeader writes the bitmap file header to the file.
|
||||
*
|
||||
*/
|
||||
private void writeBitmapFileHeader () {
|
||||
try {
|
||||
fo.write (bfType);
|
||||
fo.write (intToDWord (bfSize));
|
||||
fo.write (intToWord (bfReserved1));
|
||||
fo.write (intToWord (bfReserved2));
|
||||
fo.write (intToDWord (bfOffBits));
|
||||
}
|
||||
catch (Exception wbfh) {
|
||||
wbfh.printStackTrace ();
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* writeBitmapInfoHeader writes the bitmap information header
|
||||
* to the file.
|
||||
*
|
||||
*/
|
||||
private void writeBitmapInfoHeader () {
|
||||
try {
|
||||
fo.write (intToDWord (biSize));
|
||||
fo.write (intToDWord (biWidth));
|
||||
fo.write (intToDWord (biHeight));
|
||||
fo.write (intToWord (biPlanes));
|
||||
fo.write (intToWord (biBitCount));
|
||||
fo.write (intToDWord (biCompression));
|
||||
fo.write (intToDWord (biSizeImage));
|
||||
fo.write (intToDWord (biXPelsPerMeter));
|
||||
fo.write (intToDWord (biYPelsPerMeter));
|
||||
fo.write (intToDWord (biClrUsed));
|
||||
fo.write (intToDWord (biClrImportant));
|
||||
}
|
||||
catch (Exception wbih) {
|
||||
wbih.printStackTrace ();
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* intToWord converts an int to a word, where the return
|
||||
* value is stored in a 2-byte array.
|
||||
*
|
||||
*/
|
||||
private byte [] intToWord (int parValue) {
|
||||
byte retValue [] = new byte [2];
|
||||
retValue [0] = (byte) (parValue & 0x00FF);
|
||||
retValue [1] = (byte) ((parValue >> 8) & 0x00FF);
|
||||
return (retValue);
|
||||
}
|
||||
/*
|
||||
*
|
||||
* intToDWord converts an int to a double word, where the return
|
||||
* value is stored in a 4-byte array.
|
||||
*
|
||||
*/
|
||||
private byte [] intToDWord (int parValue) {
|
||||
byte retValue [] = new byte [4];
|
||||
retValue [0] = (byte) (parValue & 0x00FF);
|
||||
retValue [1] = (byte) ((parValue >> 8) & 0x000000FF);
|
||||
retValue [2] = (byte) ((parValue >> 16) & 0x000000FF);
|
||||
retValue [3] = (byte) ((parValue >> 24) & 0x000000FF);
|
||||
return (retValue);
|
||||
}
|
||||
}
|
46
src/org/warpgate/pi/calculator/Equazione.java
Normal file
46
src/org/warpgate/pi/calculator/Equazione.java
Normal file
@ -0,0 +1,46 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import com.rits.cloning.Cloner;
|
||||
|
||||
public class Equazione extends FunzioneDueValori {
|
||||
|
||||
public Equazione(Funzione value1, Funzione value2) {
|
||||
super(value1, value2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String simbolo() {
|
||||
return Simboli.EQUATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Termine calcola() throws Errore {
|
||||
return new Sottrazione(getVariable1().calcola(),getVariable2().calcola()).calcola();
|
||||
}
|
||||
|
||||
public Vector<Equazione> risolviPassaggio(char charIncognita) {
|
||||
Vector<Equazione> result = new Vector<Equazione>();
|
||||
result.add(this.clone());
|
||||
for (Tecnica t : Tecnica.tecniche) {
|
||||
Vector<Equazione> newResults = new Vector<Equazione>();
|
||||
final int sz = result.size();
|
||||
for (int n = 0; n < sz; n++) {
|
||||
Vector<Equazione> singleResult = t.risolvi(result.get(n));
|
||||
final int sz2 = singleResult.size();
|
||||
for (int n2 = 0; n2 < sz2; n2++) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: finire
|
||||
return result;
|
||||
}
|
||||
|
||||
public Equazione clone() {
|
||||
Cloner cloner = new Cloner();
|
||||
return cloner.deepClone(this);
|
||||
}
|
||||
|
||||
}
|
42
src/org/warpgate/pi/calculator/Incognita.java
Normal file
42
src/org/warpgate/pi/calculator/Incognita.java
Normal file
@ -0,0 +1,42 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.nevec.rjm.Rational;
|
||||
|
||||
public class Incognita {
|
||||
public char simbolo = 'X';
|
||||
public Rational esponente = Rational.ONE;
|
||||
|
||||
public Incognita(char simbolo, Rational esponente) {
|
||||
this.simbolo = simbolo;
|
||||
this.esponente = esponente;
|
||||
}
|
||||
|
||||
public Incognita(char simbolo, int a, int b) {
|
||||
this.simbolo = simbolo;
|
||||
this.esponente = new Rational(a, b);
|
||||
}
|
||||
|
||||
public Incognita(char simbolo) {
|
||||
this.simbolo = simbolo;
|
||||
this.esponente = new Rational(1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Incognita) {
|
||||
if (this.simbolo == ((Incognita) o).simbolo) {
|
||||
if (this.esponente == ((Incognita) o).esponente) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Character.getNumericValue(simbolo)*3+esponente.hashCode();
|
||||
}
|
||||
}
|
388
src/org/warpgate/pi/calculator/Incognite.java
Normal file
388
src/org/warpgate/pi/calculator/Incognite.java
Normal file
@ -0,0 +1,388 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.nevec.rjm.BigIntegerMath;
|
||||
import org.nevec.rjm.Rational;
|
||||
|
||||
public class Incognite {
|
||||
|
||||
Vector<Incognita> incognite;
|
||||
|
||||
public Incognite() {
|
||||
incognite = new Vector<Incognita>();
|
||||
}
|
||||
|
||||
public Incognite(Incognita[] value) {
|
||||
this();
|
||||
for (Incognita i : value) {
|
||||
incognite.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
public Incognite(Vector<Incognita> value) {
|
||||
this();
|
||||
incognite = value;
|
||||
}
|
||||
|
||||
public Incognite(Incognita value) {
|
||||
this();
|
||||
incognite.add(value);
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return incognite.size();
|
||||
}
|
||||
|
||||
public boolean contieneSimbolo(char simbolo) {
|
||||
for (Incognita i : incognite) {
|
||||
if (i.simbolo == simbolo) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Rational prendiEsponenteSimbolo(char simbolo) {
|
||||
for (Incognita i : incognite) {
|
||||
if (i.simbolo == simbolo) {
|
||||
return i.esponente;
|
||||
}
|
||||
}
|
||||
return new Rational(0, 1);
|
||||
}
|
||||
|
||||
public void impostaEsponenteSimbolo(char simbolo, Rational esponente) {
|
||||
for (Incognita i : incognite) {
|
||||
if (i.simbolo == simbolo) {
|
||||
i.esponente = esponente;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Incognite clone() {
|
||||
return new Incognite((Vector<Incognita>) incognite.clone()).normalize();
|
||||
}
|
||||
|
||||
public Incognite multiply(Incognite val) {
|
||||
Incognite result = new Incognite();
|
||||
//Passaggio 1: test vari
|
||||
//Se il primo gruppo di incognite è nullo allora ritorna il secondo gruppo
|
||||
if (this.count() == 0) {
|
||||
result = val.clone();
|
||||
return result;
|
||||
}
|
||||
//Se il secondo gruppo di incognite è nullo allora ritorna il primo gruppo
|
||||
if (val.count() == 0) {
|
||||
result = this.clone();
|
||||
return result;
|
||||
}
|
||||
|
||||
//Passaggio 2: le incognite doppie vengono raggruppate.
|
||||
for (Incognita i1 : incognite) {
|
||||
for (Incognita i2 : val.incognite) {
|
||||
if (i1.simbolo == i2.simbolo) {
|
||||
if (!result.contieneSimbolo(i1.simbolo)) {
|
||||
Incognita ir = new Incognita(i1.simbolo, i1.esponente.add(i2.esponente));
|
||||
result.incognite.add(ir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Passaggio 3: le incognite non ancora presenti vengono aggiunte.
|
||||
for (Incognita i : incognite) {
|
||||
if (!result.contieneSimbolo(i.simbolo)) {
|
||||
result.incognite.add(i);
|
||||
}
|
||||
}
|
||||
for (Incognita i : val.incognite) {
|
||||
if (!result.contieneSimbolo(i.simbolo)) {
|
||||
result.incognite.add(i);
|
||||
}
|
||||
}
|
||||
return result.normalize();
|
||||
}
|
||||
|
||||
public Incognite divide(Incognite val) {
|
||||
Incognite result = new Incognite();
|
||||
|
||||
//Passaggio 2: le incognite doppie vengono raggruppate.
|
||||
for (Incognita i1 : incognite) {
|
||||
for (Incognita i2 : val.incognite) {
|
||||
if (i1.simbolo == i2.simbolo) {
|
||||
if (!result.contieneSimbolo(i1.simbolo)) {
|
||||
Incognita ir = new Incognita(i1.simbolo, i1.esponente.add(i2.esponente.multiply(new Rational(-1, 1))));
|
||||
result.incognite.add(ir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Passaggio 3: le incognite non ancora presenti vengono aggiunte.
|
||||
for (Incognita i : incognite) {
|
||||
if (!result.contieneSimbolo(i.simbolo)) {
|
||||
result.incognite.add(i);
|
||||
}
|
||||
}
|
||||
for (Incognita i : val.incognite) {
|
||||
if (!result.contieneSimbolo(i.simbolo)) {
|
||||
result.incognite.add(new Incognita(i.simbolo, i.esponente.multiply(new Rational(-1, 1))));
|
||||
}
|
||||
}
|
||||
return result.normalize();
|
||||
}
|
||||
|
||||
public Incognite sqrt() {
|
||||
Incognite result = new Incognite();
|
||||
for (Incognita i1 : incognite) {
|
||||
Incognita ir = null;
|
||||
try {
|
||||
ir = new Incognita(i1.simbolo, i1.esponente.divide(new Rational(2, 1)));
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
result.incognite.add(ir);
|
||||
}
|
||||
return result.normalize();
|
||||
}
|
||||
|
||||
public Incognite normalize() {
|
||||
Incognite result = new Incognite();
|
||||
for (Incognita i1 : incognite) {
|
||||
if (i1.esponente.compareTo(Rational.ZERO) != 0) {
|
||||
result.incognite.add(i1);
|
||||
}
|
||||
}
|
||||
result.incognite.sort(new Comparator<Incognita>() {
|
||||
@Override
|
||||
public int compare(Incognita o1, Incognita o2) {
|
||||
int index1 = letterIndex(o1.simbolo);
|
||||
int index2 = letterIndex(o2.simbolo);
|
||||
return index1-index2;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte letterIndex(char l) {
|
||||
return letterIndex(l, false);
|
||||
}
|
||||
public static byte letterIndex(char l, boolean reverse) {
|
||||
int total = Simboli.incognite().length-1;
|
||||
for (byte x = 0; x < Simboli.incognite().length; x++) {
|
||||
if (Simboli.incognite()[x].equals(""+l)) {
|
||||
if (reverse) {
|
||||
return (byte) (total-x);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean compareTo(Incognite val) {
|
||||
if (this.equals(val)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object val) {
|
||||
if (val == null) return false;
|
||||
if (val instanceof Incognite) {
|
||||
Incognite ii2 = (Incognite) val;
|
||||
for (Incognita i1 : incognite) {
|
||||
boolean found = false;
|
||||
for (Incognita i2 : ii2.incognite) {
|
||||
if (i1.simbolo == i2.simbolo) {
|
||||
if (i1.esponente.compareTo(i2.esponente) != 0)
|
||||
return false;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (Incognita i1 : ii2.incognite) {
|
||||
boolean found = false;
|
||||
for (Incognita i2 : incognite) {
|
||||
if (i1.simbolo == i2.simbolo) {
|
||||
if (i1.esponente.compareTo(i2.esponente) != 0)
|
||||
return false;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String result = "";
|
||||
if (incognite.size() != 1) {
|
||||
for (Incognita i : incognite) {
|
||||
if (i.esponente.compareTo(Rational.ONE) != 0) {
|
||||
result += "("+i.simbolo+"^"+i.esponente+")";
|
||||
} else {
|
||||
result += i.simbolo;
|
||||
}
|
||||
}
|
||||
} else if (incognite.size() == 1) {
|
||||
Incognita i = incognite.get(0);
|
||||
if (i.esponente.compareTo(Rational.ONE) != 0) {
|
||||
result += ""+i.simbolo+"^"+i.esponente+"";
|
||||
} else if (i.esponente.compareTo(Rational.ONE) == 0) {
|
||||
result += i.simbolo;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Incognite lcm(Incognite val1, Incognite val2) {
|
||||
Incognite result = new Incognite();
|
||||
//Passaggio 1: test vari
|
||||
//Se il primo gruppo di incognite è nullo allora ritorna il secondo gruppo
|
||||
if (val1.count() == 0) {
|
||||
result = val2.clone();
|
||||
return result;
|
||||
}
|
||||
//Se il secondo gruppo di incognite è nullo allora ritorna il primo gruppo
|
||||
if (val2.count() == 0) {
|
||||
result = val1.clone();
|
||||
return result;
|
||||
}
|
||||
|
||||
//Passaggio 2: le incognite doppie vengono raggruppate.
|
||||
for (Incognita i1 : val1.incognite) {
|
||||
for (Incognita i2 : val2.incognite) {
|
||||
if (i1.simbolo == i2.simbolo) {
|
||||
if (!result.contieneSimbolo(i1.simbolo)) {
|
||||
Incognita ir = new Incognita(i1.simbolo);
|
||||
if (i1.esponente.compareTo(i2.esponente) > 0) {
|
||||
ir.esponente = i1.esponente;
|
||||
} else {
|
||||
ir.esponente = i2.esponente;
|
||||
}
|
||||
result.incognite.add(ir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Passaggio 3: le incognite non ancora presenti vengono aggiunte.
|
||||
for (Incognita i : val1.incognite) {
|
||||
if (!result.contieneSimbolo(i.simbolo)) {
|
||||
result.incognite.add(i);
|
||||
}
|
||||
}
|
||||
for (Incognita i : val2.incognite) {
|
||||
if (!result.contieneSimbolo(i.simbolo)) {
|
||||
result.incognite.add(i);
|
||||
}
|
||||
}
|
||||
return result.normalize();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Vector<Incognita> listaIncognite() {
|
||||
return (Vector<Incognita>) this.incognite.clone();
|
||||
}
|
||||
|
||||
public static Incognite[] normalizeBigSurdVariables(Incognite[] incognitetemp) throws Errore {
|
||||
Incognite incognitex = incognitetemp[0].clone();
|
||||
Incognite incognitey = incognitetemp[1].clone();
|
||||
Incognite incognitez = incognitetemp[2].clone();
|
||||
|
||||
Incognite newincognitex = new Incognite();
|
||||
for (Incognita i : incognitex.incognite) {
|
||||
Vector<BigInteger> divisori = BigIntegerMath.divisors(i.esponente.divide(2).denom());
|
||||
if (divisori.contains(new BigInteger("2"))) {
|
||||
newincognitex = newincognitex.multiply(new Incognite(i));
|
||||
} else {
|
||||
incognitey = incognitey.multiply(new Incognite(new Incognita(i.simbolo, i.esponente.divide(2))));
|
||||
}
|
||||
}
|
||||
incognitex = newincognitex;
|
||||
|
||||
|
||||
for (Incognita i : incognitey.incognite) {
|
||||
if (i.esponente.signum() < 0) {
|
||||
incognitey = incognitey.divide(new Incognite(i));
|
||||
incognitez = incognitez.divide(new Incognite(i));
|
||||
}
|
||||
}
|
||||
for (Incognita i : incognitez.incognite) {
|
||||
if (i.esponente.signum() < 0) {
|
||||
incognitey = incognitey.divide(new Incognite(i));
|
||||
incognitez = incognitez.divide(new Incognite(i));
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: SPOSTARE LE Y NEGATIVE SOTTO LA FRAZIONE, DALLA Y ALLA Z
|
||||
|
||||
|
||||
Incognite incogniteyresult = new Incognite();
|
||||
Incognite incognitezresult = new Incognite();
|
||||
//Le incognite doppie vengono tolte
|
||||
for (Incognita i1 : incognitey.incognite) {
|
||||
for (Incognita i2 : incognitez.incognite) {
|
||||
if (i1.simbolo == i2.simbolo) {
|
||||
if (i1.esponente.compareTo(i2.esponente) > 0) {
|
||||
incogniteyresult = incogniteyresult.multiply(new Incognite(new Incognita(i1.simbolo, i1.esponente.subtract(i2.esponente))));
|
||||
} else if (i2.esponente.compareTo(i1.esponente) > 0) {
|
||||
incognitezresult = incognitezresult.multiply(new Incognite(new Incognita(i1.simbolo, i2.esponente.subtract(i1.esponente))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Le altre incognite vengono ri-messe
|
||||
for (Incognita i : incognitey.incognite) {
|
||||
if (!incogniteyresult.contieneSimbolo(i.simbolo)) {
|
||||
incogniteyresult = incogniteyresult.multiply(new Incognite(i));
|
||||
}
|
||||
}
|
||||
for (Incognita i : incognitez.incognite) {
|
||||
if (!incognitezresult.contieneSimbolo(i.simbolo)) {
|
||||
incognitezresult = incognitezresult.multiply(new Incognite(i));
|
||||
}
|
||||
}
|
||||
|
||||
incognitey = incogniteyresult;
|
||||
incognitez = incognitezresult;
|
||||
|
||||
return new Incognite[]{incognitex, incognitey, incognitez};
|
||||
}
|
||||
|
||||
public static int priorità(Incognite ii) {
|
||||
double priorità = 0;
|
||||
double letterMax = 0;
|
||||
for(Incognita i : ii.incognite) {
|
||||
int lettIndex = letterIndex(i.simbolo, true);
|
||||
if (lettIndex > letterMax) {
|
||||
letterMax = lettIndex;
|
||||
}
|
||||
}
|
||||
priorità+=letterMax*100000;
|
||||
|
||||
for(Incognita i : ii.incognite) {
|
||||
int lettIndex = letterIndex(i.simbolo, true);
|
||||
if (letterMax == lettIndex) {
|
||||
priorità+=i.esponente.doubleValue()*100000;
|
||||
}
|
||||
priorità+=+i.esponente.doubleValue();
|
||||
}
|
||||
return (int) priorità;
|
||||
}
|
||||
}
|
6
src/org/warpgate/pi/calculator/Keyboard.java
Normal file
6
src/org/warpgate/pi/calculator/Keyboard.java
Normal file
@ -0,0 +1,6 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
public class Keyboard {
|
||||
public static boolean alpha = false;
|
||||
public static boolean shift = false;
|
||||
}
|
63
src/org/warpgate/pi/calculator/ParteSistema.java
Normal file
63
src/org/warpgate/pi/calculator/ParteSistema.java
Normal file
@ -0,0 +1,63 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.nevec.rjm.Rational;
|
||||
import org.warp.engine.Display;
|
||||
|
||||
public class ParteSistema extends FunzioneAnteriore {
|
||||
|
||||
public ParteSistema(Funzione value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String simbolo() {
|
||||
return Simboli.SYSTEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Termine calcola() throws NumberFormatException, Errore {
|
||||
//TODO implementare il calcolo dei sistemi
|
||||
return variable.calcola();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(int x, int y, Display g, boolean small) {
|
||||
small = false;
|
||||
final int h = this.getHeight(small)-1;
|
||||
final int varLine = variable.getLine(small);
|
||||
final int paddingTop = 3;
|
||||
final int spazioSotto = (h-3-2)/2+paddingTop;
|
||||
final int spazioSopra = h - spazioSotto;
|
||||
variable.draw(x+5, y+paddingTop, g, small);
|
||||
g.setColor(Color.black);
|
||||
g.drawOrthoLine(x+2, y+0, x+3, y+0);
|
||||
g.drawOrthoLine(x+1, y+1, x+1, y+spazioSotto/2);
|
||||
g.drawOrthoLine(x+2, y+spazioSotto/2+1, x+2, y+spazioSotto-1);
|
||||
g.drawOrthoLine(x+0, y+spazioSotto, x+1, y+spazioSotto);
|
||||
g.drawOrthoLine(x+2, y+spazioSotto+1, x+2, y+spazioSotto+spazioSopra/2-1);
|
||||
g.drawOrthoLine(x+1, y+spazioSotto+spazioSopra/2, x+1, y+h-1);
|
||||
g.drawOrthoLine(x+2, y+h, x+3, y+h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return 5+getVariable().getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(boolean small) {
|
||||
small = false;
|
||||
int h1 = 3+getVariable().getHeight(small)+2;
|
||||
return h1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine(boolean small) {
|
||||
small = false;
|
||||
int h1 = 3+getVariable().getLine(small);
|
||||
return h1;
|
||||
}
|
||||
}
|
22
src/org/warpgate/pi/calculator/Sottrazione.java
Normal file
22
src/org/warpgate/pi/calculator/Sottrazione.java
Normal file
@ -0,0 +1,22 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
|
||||
public class Sottrazione extends FunzioneDueValori {
|
||||
|
||||
public Sottrazione(Funzione value1, Funzione value2) {
|
||||
super(value1, value2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String simbolo() {
|
||||
return Simboli.SUBTRACTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Termine calcola() throws Errore {
|
||||
return getVariable1().calcola().add(getVariable2().calcola().multiply(new Termine("-1")));
|
||||
}
|
||||
|
||||
}
|
9
src/org/warpgate/pi/calculator/Tecnica.java
Normal file
9
src/org/warpgate/pi/calculator/Tecnica.java
Normal file
@ -0,0 +1,9 @@
|
||||
package org.warpgate.pi.calculator;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
public interface Tecnica {
|
||||
public static final Tecnica[] tecniche = new Tecnica[] {};
|
||||
|
||||
public abstract Vector<Equazione> risolvi(Equazione equazione);
|
||||
}
|
29
src/org/warpgate/pi/calculator/screens/EmptyScreen.java
Normal file
29
src/org/warpgate/pi/calculator/screens/EmptyScreen.java
Normal file
@ -0,0 +1,29 @@
|
||||
package org.warpgate.pi.calculator.screens;
|
||||
|
||||
import org.warp.engine.lwjgl.Screen;
|
||||
|
||||
public class EmptyScreen extends Screen {
|
||||
|
||||
public float endLoading;
|
||||
|
||||
@Override
|
||||
public void init() throws InterruptedException {
|
||||
canBeInHistory = true;
|
||||
endLoading = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRender(float dt) {
|
||||
endLoading += dt;
|
||||
if (d.loading & endLoading >= 2.5) {
|
||||
d.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
203
src/org/warpgate/pi/calculator/screens/EquationScreen.java
Normal file
203
src/org/warpgate/pi/calculator/screens/EquationScreen.java
Normal file
@ -0,0 +1,203 @@
|
||||
package org.warpgate.pi.calculator.screens;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.warp.engine.lwjgl.Screen;
|
||||
import org.warpgate.pi.calculator.Calculator;
|
||||
import org.warpgate.pi.calculator.Errore;
|
||||
import org.warpgate.pi.calculator.Errori;
|
||||
import org.warpgate.pi.calculator.Funzione;
|
||||
import org.warpgate.pi.calculator.Main;
|
||||
import org.warpgate.pi.calculator.Parentesi;
|
||||
import org.warpgate.pi.calculator.RisultatoEquazione;
|
||||
import org.warpgate.pi.calculator.Termine;
|
||||
|
||||
public class EquationScreen extends Screen {
|
||||
|
||||
public float endLoading;
|
||||
public static volatile String equazione = "";
|
||||
public static Parentesi f;
|
||||
public static Funzione f2;
|
||||
public static int ew1;
|
||||
public static int ew2;
|
||||
public static int eh2;
|
||||
public static int x1;
|
||||
public static int x2;
|
||||
public static boolean requiresleep1;
|
||||
public static boolean requiresleep2;
|
||||
public static boolean aftersleep;
|
||||
public static boolean autoscroll;
|
||||
|
||||
@Override
|
||||
public void init() throws InterruptedException {
|
||||
canBeInHistory = true;
|
||||
endLoading = 0;
|
||||
try {
|
||||
/* Fine caricamento */
|
||||
|
||||
//Parentesi f = new Parentesi("(Ⓐ(2X)*3Y)/(5Z^2)+(Ⓐ(11A)*13B)/(7CZ)=19XZ");
|
||||
//PARENTESI CON CALCOLI
|
||||
//Funzione f = new Sottrazione(new Somma(new Parentesi("Ⓐ9/2+Ⓐ7/2", "").calcola(), new Termine("3.5")), new Parentesi("3*2√14","").calcola());
|
||||
//PARENTESI CON DUE NUMERI FRAZIONALI COMPLETI CON INCOGNITE:
|
||||
//Funzione f = new Parentesi("(Ⓐ(2X)*3Y)/(5Z^2)+(Ⓐ(11A)*13B)/(7CZ)", "");
|
||||
//PARENTESI CON DUE NUMERI FRAZIONALI DISALLINEATI GRAFICAMENTE:
|
||||
//Funzione f = new Parentesi("((5^2-1)/2)/5-5/(5/2)=2", "");
|
||||
//TERMINE DI PROVA COMPLETO:
|
||||
//Funzione f = new Termine(new NumeroAvanzato(new Rational(3, 2), new Rational(7, 1), new Incognite(new Incognita('X', Rational.ONE)), new Incognite(new Incognita('Y', Rational.ONE)), new Incognite(new Incognita('z', Rational.ONE))));
|
||||
//PARENTESI REALISTICA CON INCOGNITE:
|
||||
//Funzione f = new Equazione(new Parentesi("X^2+(MX-M+4)^2-4X-4(MX-M+4)^2+7", ""), new Termine("0"));
|
||||
//POTENZA:
|
||||
//Funzione f = new Parentesi("(MX-M+4)^2", "");
|
||||
//NUMERO SEMPLICE LUNGO:
|
||||
//Funzione f = new Parentesi("-1219999799999996934.42229", "");
|
||||
//:
|
||||
//Funzione f = new Parentesi("5Y+XY=2", "")
|
||||
|
||||
equazione = "0";
|
||||
f = new Parentesi(equazione);
|
||||
f2 = f.calcolaSistema();
|
||||
|
||||
|
||||
ew1 = f.getWidth();
|
||||
ew2 = f2.getWidth();
|
||||
eh2 = f2.getHeight(false);
|
||||
x1 = 2;
|
||||
x2 = 2;
|
||||
requiresleep1 = false;
|
||||
requiresleep2 = false;
|
||||
aftersleep = false;
|
||||
autoscroll = false;
|
||||
|
||||
long start = System.nanoTime();
|
||||
Termine result = Calculator.calcolarisultato("((5Ⓑ2+3√(100/0.1))*Ⓐ7+9/15*2√(26/2))/21");
|
||||
long end = System.nanoTime();
|
||||
long timeElapsed = end-start;
|
||||
System.out.println("RESULT: " + result);
|
||||
System.out.println("DECIMAl RESULT: " + result.getTerm().toBigDecimal());
|
||||
System.out.println("Time elapsed: " + (double) timeElapsed / 1000000 + " milliseconds\n");
|
||||
|
||||
|
||||
start = System.nanoTime();
|
||||
RisultatoEquazione eresult = Calculator.calcolaequazione("((5Ⓑ2+3√(100/0.1))*Ⓐ7+9/15*2√(26/2))/21=(175*(2√7)+3*(2√13))/105");
|
||||
end = System.nanoTime();
|
||||
timeElapsed = end-start;
|
||||
System.out.println("Is an equation: " + eresult.isAnEquation);
|
||||
System.out.println("L-R: " + eresult.LR);
|
||||
System.out.println("Time elapsed: " + (double) timeElapsed / 1000000 + " milliseconds\n");
|
||||
} catch (Errore e) {
|
||||
d.setBackground(0.99609375f,102f/256f,34f/256f);
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
|
||||
d.error = e.id.toString();
|
||||
System.err.println(e.id);
|
||||
}
|
||||
}
|
||||
|
||||
public void calcola(String eqn) {
|
||||
equazione = eqn.replace("sqrt", "Ⓐ").replace("^", "Ⓑ");
|
||||
try {
|
||||
f = new Parentesi(equazione);
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
f2 = f.calcolaSistema();
|
||||
} catch (Errore e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ew1 = f.getWidth();
|
||||
ew2 = f2.getWidth();
|
||||
eh2 = f2.getHeight(false);
|
||||
x1 = 2;
|
||||
x2 = 2;
|
||||
requiresleep1 = false;
|
||||
requiresleep2 = false;
|
||||
aftersleep = false;
|
||||
autoscroll = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRender(float dt) {
|
||||
endLoading += dt;
|
||||
if (endLoading >= 2.5) {
|
||||
d.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
d.setBackground(0.796875f, 0.90234375f, 0.828125f);
|
||||
try {
|
||||
// long delta = System.currentTimeMillis();
|
||||
//
|
||||
// if (equazione == "") {
|
||||
// throw new Errore(Errori.SYNTAX_ERROR);
|
||||
// } else {
|
||||
// if (ew1 + x1 + 5 > screenSize[0] && !requiresleep1 && autoscroll) {
|
||||
// x1-=1;
|
||||
// } else if(autoscroll) {
|
||||
// requiresleep1 = true;
|
||||
// }
|
||||
//
|
||||
// if (ew2 + x2 + 5 > screenSize[0] && !requiresleep2 && autoscroll) {
|
||||
// x2-=1;
|
||||
// } else if(autoscroll) {
|
||||
// requiresleep2 = true;
|
||||
// }
|
||||
//
|
||||
// if (requiresleep1 && requiresleep2 && autoscroll) {
|
||||
// requiresleep1 = false;
|
||||
// requiresleep2 = false;
|
||||
// try {
|
||||
// Thread.sleep(500);
|
||||
// } catch (InterruptedException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// x1 = 2;
|
||||
// x2 = 2;
|
||||
// aftersleep = true;
|
||||
// }
|
||||
//
|
||||
// f.draw(x1,2,d, false);
|
||||
// f2.draw(x2,screenSize[1]-2-eh2,d, false);
|
||||
// }
|
||||
//
|
||||
// if (aftersleep && autoscroll) {
|
||||
// aftersleep = false;
|
||||
// try {
|
||||
// Thread.sleep(500);
|
||||
// } catch (InterruptedException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// delta = System.currentTimeMillis() - delta;
|
||||
// if (50-delta > 0 && autoscroll) {
|
||||
// Thread.sleep(50-delta);
|
||||
// }
|
||||
// } catch (InterruptedException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
if (false) {
|
||||
throw new Errore(Errori.SYNTAX_ERROR);
|
||||
}
|
||||
} catch (Errore e) {
|
||||
d.setBackground(0.99609375f,102f/256f,34f/256f);
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n");
|
||||
d.error = e.id.toString();
|
||||
System.err.println(e.id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user