king-2.21.120420/ 0000755 0000000 0000000 00000000000 11756425773 011634 5 ustar root root king-2.21.120420/king/ 0000755 0000000 0000000 00000000000 11756425772 012563 5 ustar root root king-2.21.120420/king/Manifest.mf 0000644 0000000 0000000 00000000072 11531212702 014626 0 ustar root root Main-Class: king.KingMain
Class-Path: itext.jar jogl.jar
king-2.21.120420/king/build.xml 0000644 0000000 0000000 00000024314 11677362242 014402 0 ustar root root
KiNG kinemage viewer
king-2.21.120420/king/tutorial/ 0000755 0000000 0000000 00000000000 11744310054 014405 5 ustar root root king-2.21.120420/king/tutorial/JoglTumblingObject.html 0000644 0000000 0000000 00000000244 11531212656 021022 0 ustar root root
JoglTumblingObject requires that the JOGL native libraries be installed, so it is available as an application rather than an applet.
king-2.21.120420/king/tutorial/src/ 0000755 0000000 0000000 00000000000 11744310054 015174 5 ustar root root king-2.21.120420/king/tutorial/src/JoglTumblingObject.java 0000644 0000000 0000000 00000011143 11531212656 021566 0 ustar root root package king.tutorial;
import king.core.*;
import king.points.*;
import king.painters.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
/**
* JoglTumblingObject
creates a decorative spiral ornament and sets it rotating.
*
* Copyright (C) 2006 by Ian W. Davis. All rights reserved.
*
Begun on Fri Dec 8 13:27:16 EST 2006
*/
public class JoglTumblingObject extends JFrame implements ActionListener, GLEventListener
{
final boolean use3d = true;
Kinemage kin = null;
KView view = null;
Engine2D engine2 = null;
JoglEngine3D engine3 = null;
GLCanvas canvas = null;
Dimension glSize = new Dimension();
Timer timer = null;
static public void main(String[] args) { new JoglTumblingObject(); }
public JoglTumblingObject()
{
super("JoglTumblingObject");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
kin = createKinemage();
view = new KView(kin);
view.setSpan(1.2f * view.getSpan());
engine2 = new Engine2D();
engine2.usePerspective = true;
engine3 = new JoglEngine3D();
engine3.usePerspective = true;
// Create and listen to an OpenGL canvas
GLCapabilities capabilities = new GLCapabilities();
capabilities.setDoubleBuffered(true); // usually enabled by default, but to be safe...
int fsaaNumSamples = 4;
capabilities.setSampleBuffers(fsaaNumSamples > 1); // enables/disables full-scene antialiasing (FSAA)
capabilities.setNumSamples(fsaaNumSamples); // sets number of samples for FSAA (default is 2)
canvas = new GLCanvas(capabilities);
canvas.addGLEventListener(this); // calls display(), reshape(), etc.
canvas.setPreferredSize(new Dimension(400,400));
this.getContentPane().add(canvas);
this.pack();
this.show();
timer = new Timer(1000 / 30, this);
timer.start();
}
Kinemage createKinemage()
{
Kinemage k = new Kinemage();
KGroup g = new KGroup();
k.add(g);
KPaint[] colors = { KPalette.red, KPalette.green, KPalette.gold,
KPaint.createLightweightHSV("silver", 240, 3, 90, 240, 3, 10) };
for(int c = 0; c < colors.length; c++)
{
KList list = new KList(KList.BALL);
//list.setOn(false);
list.setColor(colors[c]);
list.setRadius(0.1f);
g.add(list);
double offset = (2.0 * Math.PI * c) / colors.length;
for(double y = -1; y <= 1.001; y += list.getRadius())
{
double r = 1 - Math.abs(y);
double theta = (2.0 * Math.PI * y) + offset;
BallPoint pt = new BallPoint("");
pt.setXYZ(r * Math.cos(theta), y, r * Math.sin(theta));
list.add(pt);
}
}
for(int c = 0; c < colors.length; c++)
{
KList list = new KList(KList.VECTOR);
//list.setOn(false);
list.setColor(colors[c]);
list.setWidth(4);
g.add(list);
double offset = (2.0 * Math.PI * c) / colors.length;
VectorPoint prevPt = null;
for(double y = -1; y <= 1.001; y += 0.02)
{
double r = 1 - Math.abs(y);
double theta = (2.0 * Math.PI * y) + offset;
VectorPoint pt = new VectorPoint("", prevPt);
pt.setXYZ(r * Math.cos(theta), y, r * Math.sin(theta));
list.add(pt);
prevPt = pt;
}
}
return k;
}
public void actionPerformed(ActionEvent ev)
{
view.rotateY( (float) Math.toRadians(1.0) );
canvas.repaint();
}
public void init(GLAutoDrawable drawable)
{}
public void display(GLAutoDrawable drawable)
{
if(use3d)
{
engine3.render(kin, view, new Rectangle(this.glSize), drawable.getGL());
}
else
{
JoglPainter painter = new JoglPainter(drawable);
engine2.render(kin, view, new Rectangle(this.glSize), painter);
}
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
{
this.glSize.setSize(width, height);
}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged)
{}
}//class
king-2.21.120420/king/tutorial/src/JoglDiveDebug.java 0000644 0000000 0000000 00000031144 11531212656 020517 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.tutorial;
import king.core.*;
import king.points.*;
import king.painters.*;
import driftwood.r3.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
//}}}
/**
* JoglDiveDebug
is used for testing out rendering methods for
* the Duke DiVE (6-sided VR cave).
*
*
Copyright (C) 2006 by Ian W. Davis. All rights reserved.
*
Begun on Fri Dec 8 13:27:16 EST 2006
*/
public class JoglDiveDebug extends JFrame implements ActionListener
{
//{{{ CLASS: Screen
//##############################################################################
public class Screen implements GLEventListener
{
public GLCanvas canvas = null;
public JoglEngine3D engine = null;
public Dimension glSize = new Dimension();
String label;
public Screen(GLCapabilities capabilities, String label)
{
this.label = label;
canvas = new GLCanvas(capabilities);
canvas.addGLEventListener(this); // calls display(), reshape(), etc.
engine = new JoglEngine3D();
engine.usePerspective = true;
engine.setFont(18);
engine.caveClipping = true;
}
public void init(GLAutoDrawable drawable)
{}
public void display(GLAutoDrawable drawable)
{
//System.err.println(label);
GL gl = drawable.getGL();
//byte[] b = new byte[1];
//gl.glGetBooleanv(GL.GL_STEREO, b, 0);
//gl.glGetBooleanv(GL.GL_DOUBLEBUFFER, b, 0);
//System.err.println(b[0]);
//int[] i = new int[1];
//gl.glGetIntegerv(GL.GL_DRAW_BUFFER, i, 0);
//System.err.println(i[0]+" === "+GL.GL_BACK_LEFT+" =/= "+GL.GL_BACK_RIGHT);
engine.render(kin, view, new Rectangle(glSize), gl, eyePos);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
{
this.glSize.setSize(width, height);
}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged)
{}
}
//}}}
//{{{ Variable definitions
//##############################################################################
Kinemage kin = null;
KView view = null;
Triple eyePos = new Triple(0, 0, 0);
Screen[] screens = null;
Timer timer = null;
boolean stereo = false;
//}}}
//{{{ main, Constructor(s)
//##############################################################################
static public void main(String[] args) { new JoglDiveDebug(); }
public JoglDiveDebug()
{
super("JoglDiveDebug");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setUndecorated(true); // no window border or controls
kin = createKinemage();
view = new KView(kin);
view.setSpan(1.2f * view.getSpan());
view.setClip(3); // extra depth
//view.setCenter(0, 0, 2);
//createScreens();
createAltScreens();
Container cp = new Panel();
cp.setLayout(null);
for(Screen s : screens)
if(s != null) cp.add(s.canvas);
this.setContentPane(cp);
this.pack();
this.show();
// Only way to hide the mouse cursor in Java -- make it transparent.
int[] pixels = new int[16 * 16];
Image image = Toolkit.getDefaultToolkit().createImage(new java.awt.image.MemoryImageSource(16, 16, pixels, 0, 16));
Cursor transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(0, 0), "invisiblecursor");
this.setCursor(transparentCursor);
// Puts the window in full screen mode. Seems to work OK with JOGL.
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
gd.setFullScreenWindow(this); // should be done after becoming visible
timer = new Timer(1000 / 30, this);
timer.start();
}
//}}}
//{{{ createScreens
//##############################################################################
/** 6 walls of a CAVE -- unfolded cube */
void createScreens()
{
// Set up parameters for rendering
GLCapabilities capabilities = new GLCapabilities();
capabilities.setDoubleBuffered(true); // usually enabled by default, but to be safe...
int fsaaNumSamples = 4;
capabilities.setSampleBuffers(fsaaNumSamples > 1); // enables/disables full-scene antialiasing (FSAA)
capabilities.setNumSamples(fsaaNumSamples); // sets number of samples for FSAA (default is 2)
capabilities.setStereo(stereo);
// Allocate screens[]
this.screens = new Screen[6];
Screen s;
GLCanvas c;
JoglEngine3D e;
final int size = 300;
// center / straight ahead
s = screens[0] = new Screen(capabilities, "front");
e = s.engine;
e.screenCenterPos = new Triple(0, 0, -size/2.0);
e.screenNormalVec = new Triple(0, 0, 1);
c = s.canvas;
c.setBounds(1*size, 1*size, size, size);
// right
s = screens[1] = new Screen(capabilities, "right");
e = s.engine;
e.screenCenterPos = new Triple(size/2.0, 0, 0);
e.screenNormalVec = new Triple(-1, 0, 0);
c = s.canvas;
c.setBounds(2*size, 1*size, size, size);
// left
s = screens[2] = new Screen(capabilities, "left");
e = s.engine;
e.screenCenterPos = new Triple(-size/2.0, 0, 0);
e.screenNormalVec = new Triple(1, 0, 0);
c = s.canvas;
c.setBounds(0*size, 1*size, size, size);
// Top and bottom have very unusual "up" vectors.
// I'm not sure why these values are the right answers,
// but they produce the expected results.
// top
s = screens[3] = new Screen(capabilities, "top");
e = s.engine;
e.screenCenterPos = new Triple(0, size/2.0, 0);
e.screenNormalVec = new Triple(0, -1, 0);
e.screenUpVec = new Triple(0, 0, 1); // can't be || to normal
c = s.canvas;
c.setBounds(1*size, 0*size, size, size);
// bottom
s = screens[4] = new Screen(capabilities, "bottom");
e = s.engine;
e.screenCenterPos = new Triple(0, -size/2.0, 0);
e.screenNormalVec = new Triple(0, 1, 0);
e.screenUpVec = new Triple(0, 0, -1); // can't be || to normal
c = s.canvas;
c.setBounds(1*size, 2*size, size, size);
// back
s = screens[5] = new Screen(capabilities, "back");
e = s.engine;
e.screenCenterPos = new Triple(0, 0, size/2.0);
e.screenNormalVec = new Triple(0, 0, -1);
e.screenUpVec = new Triple(0, 1, 0);
c = s.canvas;
c.setBounds(3*size, 1*size, size, size);
}
//}}}
//{{{ createAltScreens
//##############################################################################
/** 5 screens side-by-side -- tiled wall display */
void createAltScreens()
{
// Set up parameters for rendering
GLCapabilities capabilities = new GLCapabilities();
capabilities.setDoubleBuffered(true); // usually enabled by default, but to be safe...
int fsaaNumSamples = 4;
capabilities.setSampleBuffers(fsaaNumSamples > 1); // enables/disables full-scene antialiasing (FSAA)
capabilities.setNumSamples(fsaaNumSamples); // sets number of samples for FSAA (default is 2)
capabilities.setStereo(stereo);
// Allocate screens[]
this.screens = new Screen[6];
Screen s;
GLCanvas c;
JoglEngine3D e;
final int size = 300;
// center / straight ahead
s = screens[0] = new Screen(capabilities, "front");
e = s.engine;
e.screenCenterPos = new Triple(0, 0, -size/2.0);
c = s.canvas;
c.setBounds(1*size, 1*size, size, size);
// right
s = screens[1] = new Screen(capabilities, "right");
e = s.engine;
e.screenCenterPos = new Triple(size, 0, -size/2.0);
c = s.canvas;
c.setBounds(2*size, 1*size, size, size);
// left
s = screens[2] = new Screen(capabilities, "left");
e = s.engine;
e.screenCenterPos = new Triple(-size, 0, -size/2.0);
c = s.canvas;
c.setBounds(0*size, 1*size, size, size);
// top
s = screens[3] = new Screen(capabilities, "top");
e = s.engine;
e.screenCenterPos = new Triple(0, size, -size/2.0);
c = s.canvas;
c.setBounds(1*size, 0*size, size, size);
// bottom
s = screens[4] = new Screen(capabilities, "bottom");
e = s.engine;
e.screenCenterPos = new Triple(0, -size, -size/2.0);
c = s.canvas;
c.setBounds(1*size, 2*size, size, size);
}
//}}}
//{{{ createKinemage
//##############################################################################
Kinemage createKinemage()
{
Kinemage k = new Kinemage();
KGroup g = new KGroup();
k.add(g);
KPaint[] colors = { KPalette.red, KPalette.green, KPalette.gold,
KPaint.createLightweightHSV("silver", 240, 3, 90, 240, 3, 10) };
for(int c = 0; c < colors.length; c++)
{
KList list = new KList(KList.BALL);
//list.setOn(false);
list.setColor(colors[c]);
list.setRadius(0.1f);
g.add(list);
double offset = (2.0 * Math.PI * c) / colors.length;
for(double y = -1; y <= 1.001; y += list.getRadius())
{
double r = 1 - Math.abs(y);
double theta = (2.0 * Math.PI * y) + offset;
BallPoint pt = new BallPoint("");
pt.setXYZ(r * Math.cos(theta), y, r * Math.sin(theta));
list.add(pt);
}
}
for(int c = 0; c < colors.length; c++)
{
KList list = new KList(KList.VECTOR);
//list.setOn(false);
list.setColor(colors[c]);
list.setWidth(4);
g.add(list);
double offset = (2.0 * Math.PI * c) / colors.length;
VectorPoint prevPt = null;
for(double y = -1; y <= 1.001; y += 0.02)
{
double r = 1 - Math.abs(y);
double theta = (2.0 * Math.PI * y) + offset;
VectorPoint pt = new VectorPoint("", prevPt);
pt.setXYZ(r * Math.cos(theta), y, r * Math.sin(theta));
list.add(pt);
prevPt = pt;
}
}
KList list = new KList(KList.TRIANGLE);
list.setOn(false);
list.setColor(KPalette.gray);
g.add(list);
TrianglePoint prevPt = null;
for(double y = -1; y <= 1.001; y += 0.02)
{
double r = 1 - Math.abs(y);
double theta = (2.0 * Math.PI * y);
TrianglePoint pt = new TrianglePoint("", prevPt);
pt.setXYZ(r * Math.cos(theta), y-0.1, r * Math.sin(theta));
list.add(pt);
prevPt = pt;
pt = new TrianglePoint("", prevPt);
pt.setXYZ(r * Math.cos(theta), y+0.1, r * Math.sin(theta));
list.add(pt);
prevPt = pt;
}
list = new KList(KList.LABEL);
//list.setOn(false);
list.setColor(KPalette.deadwhite);
g.add(list);
LabelPoint l1 = new LabelPoint("X-axis");
l1.setXYZ(0.5, 0, 0);
l1.setColor(KPalette.pinktint);
list.add(l1);
LabelPoint l2 = new LabelPoint("Y-axis");
l2.setXYZ(0, 0.5, 0);
l2.setColor(KPalette.greentint);
list.add(l2);
LabelPoint l3 = new LabelPoint("Z-axis");
l3.setXYZ(0, 0, 0.5);
l3.setColor(KPalette.bluetint);
list.add(l3);
return k;
}
//}}}
//{{{ actionPerformed
//##############################################################################
public void actionPerformed(ActionEvent ev)
{
view.rotateY( (float) Math.toRadians(1.0) );
for(Screen s : screens)
if(s != null) s.canvas.repaint();
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/tutorial/src/TumblingObject.java 0000644 0000000 0000000 00000004770 11531212656 020762 0 ustar root root package king.tutorial;
import king.core.*;
import king.points.*;
import king.painters.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
/**
* TumblingObject
creates a decorative spiral ornament and sets it rotating.
*
*
Copyright (C) 2006 by Ian W. Davis. All rights reserved.
*
Begun on Fri Dec 8 13:27:16 EST 2006
*/
public class TumblingObject extends JApplet implements ActionListener
{
Kinemage kin = null;
KView view = null;
Engine2D engine = null;
HighQualityPainter painter = null;
Timer timer = null;
public void init()
{
super.init();
kin = createKinemage();
view = new KView(kin);
view.setSpan(1.2f * view.getSpan());
engine = new Engine2D();
engine.usePerspective = true;
painter = new HighQualityPainter(true);
timer = new Timer(1000 / 30, this);
}
public void start()
{
super.start();
timer.start();
}
public void stop()
{
timer.stop();
super.stop();
}
public void destroy()
{
kin = null;
view = null;
engine = null;
painter = null;
super.destroy();
}
Kinemage createKinemage()
{
Kinemage k = new Kinemage();
KGroup g = new KGroup();
k.add(g);
KPaint[] colors = { KPalette.red, KPalette.green, KPalette.gold,
KPaint.createLightweightHSV("silver", 240, 3, 90, 240, 3, 10) };
for(int c = 0; c < colors.length; c++)
{
KList list = new KList(KList.BALL);
list.setColor(colors[c]);
list.setRadius(0.05f);
g.add(list);
double offset = (2.0 * Math.PI * c) / colors.length;
for(double y = -1; y <= 1; y += 0.05)
{
double r = 1 - Math.abs(y);
double theta = (2.0 * Math.PI * y) + offset;
BallPoint pt = new BallPoint("");
pt.setXYZ(r * Math.cos(theta), y, r * Math.sin(theta));
list.add(pt);
}
}
return k;
}
public void actionPerformed(ActionEvent ev)
{
view.rotateY( (float) Math.toRadians(1.0) );
this.repaint();
}
public void paint(Graphics g)
{
painter.setGraphics( (Graphics2D) g );
engine.render(kin, view, this.getBounds(), painter);
}
}//class
king-2.21.120420/king/tutorial/TumblingObject.html 0000644 0000000 0000000 00000000212 11531212656 020201 0 ustar root root
king-2.21.120420/king/1.x_src/ 0000755 0000000 0000000 00000000000 11744310052 014015 5 ustar root root king-2.21.120420/king/1.x_src/king/ 0000755 0000000 0000000 00000000000 11744310054 014747 5 ustar root root king-2.21.120420/king/1.x_src/king/EDMapPlugin.java 0000644 0000000 0000000 00000032357 11531212674 017734 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.net.*;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
import driftwood.isosurface.*;
import driftwood.util.*;
//}}}
/**
* EDMapPlugin
provides file/URL opening services
* to launch the EDMapWindows that control individual maps.
*
* Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Tue Apr 1 13:45:27 EST 2003
*/
public class EDMapPlugin extends Plugin implements ListSelectionListener
{
//{{{ Constants
static final String MAPTYPE_O = "O map (DSN6/Brix)";
static final String MAPTYPE_XPLOR = "XPLOR map (ASCII format)";
static final String MAPTYPE_CCP4 = "CCP4 map (type 2)";
//}}}
//{{{ Variable definitions
//##################################################################################################
JFileChooser filechooser = null;
JDialog urlchooser = null;
JList urlList = null;
JTextField urlField = null;
boolean urlChooserOK = false;
SuffixFileFilter omapFilter, xmapFilter, ccp4Filter, mapFilter;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public EDMapPlugin(ToolBox tb)
{
super(tb);
makeFileFilters();
}
//}}}
//{{{ makeFileFilters
//##################################################################################################
void makeFileFilters()
{
omapFilter = new SuffixFileFilter("O maps (DSN6/Brix)");
omapFilter.addSuffix(".brix");
omapFilter.addSuffix(".brix.gz");
omapFilter.addSuffix(".dsn6");
omapFilter.addSuffix(".dsn6.gz");
omapFilter.addSuffix(".dn6");
omapFilter.addSuffix(".dn6.gz");
omapFilter.addSuffix(".omap");
omapFilter.addSuffix(".omap.gz");
xmapFilter = new SuffixFileFilter("XPLOR maps (ASCII format)");
xmapFilter.addSuffix(".xmap");
xmapFilter.addSuffix(".xmap.gz");
xmapFilter.addSuffix(".xplor");
xmapFilter.addSuffix(".xplor.gz");
ccp4Filter = new SuffixFileFilter("CCP4 maps (type 2)");
ccp4Filter.addSuffix(".ccp4");
ccp4Filter.addSuffix(".ccp4.gz");
ccp4Filter.addSuffix(".mbk");
ccp4Filter.addSuffix(".mbk.gz");
mapFilter = new SuffixFileFilter("All electron density maps");
mapFilter.addSuffix(".ccp4");
mapFilter.addSuffix(".ccp4.gz");
mapFilter.addSuffix(".mbk");
mapFilter.addSuffix(".mbk.gz");
mapFilter.addSuffix(".xmap");
mapFilter.addSuffix(".xmap.gz");
mapFilter.addSuffix(".xplor");
mapFilter.addSuffix(".xplor.gz");
mapFilter.addSuffix(".brix");
mapFilter.addSuffix(".brix.gz");
mapFilter.addSuffix(".dsn6");
mapFilter.addSuffix(".dsn6.gz");
mapFilter.addSuffix(".dn6");
mapFilter.addSuffix(".dn6.gz");
mapFilter.addSuffix(".omap");
mapFilter.addSuffix(".omap.gz");
mapFilter.addSuffix(".map");
mapFilter.addSuffix(".map.gz");
}
//}}}
//{{{ makeFileChooser
//##################################################################################################
void makeFileChooser()
{
// Make actual file chooser -- will throw an exception if we're running as an Applet
filechooser = new JFileChooser();
String currdir = System.getProperty("user.dir");
if(currdir != null) filechooser.setCurrentDirectory(new File(currdir));
filechooser.addChoosableFileFilter(mapFilter);
filechooser.addChoosableFileFilter(omapFilter);
filechooser.addChoosableFileFilter(xmapFilter);
filechooser.addChoosableFileFilter(ccp4Filter);
filechooser.setFileFilter(mapFilter);
}
//}}}
//{{{ makeURLChooser
//##################################################################################################
void makeURLChooser()
{
// Make actual URL chooser
urlList = new FatJList(150, 12);
JApplet applet = kMain.getApplet();
if(applet != null)
{
String maps = applet.getParameter("edmapList");
if(maps != null)
{
String[] maplist = Strings.explode(maps, ' ');
urlList.setListData(maplist);
}
}
urlList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
urlList.addListSelectionListener(this);
JScrollPane listScroll = new JScrollPane(urlList);
// Make an (editable) URL line
urlField = new JTextField(20);
// Make the command buttons
JButton btnOK = new JButton(new ReflectiveAction("OK", null, this, "onUrlOk"));
JButton btnCancel = new JButton(new ReflectiveAction("Cancel", null, this, "onUrlCancel"));
// Put it all together in a content pane
TablePane2 cp = new TablePane2();
cp.center().middle().insets(6).memorize();
cp.addCell(listScroll,2,1);
cp.newRow();
cp.weights(0,1).addCell(new JLabel("URL:")).hfill(true).addCell(urlField);
cp.newRow().startSubtable(2,1).center().insets(1,4,1,4).memorize();
cp.addCell(btnOK).addCell(btnCancel).endSubtable();
urlchooser = new JDialog(kMain.getTopWindow(), "ED Map URLs", true);
urlchooser.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
urlchooser.setContentPane(cp);
urlchooser.pack();
urlchooser.setLocationRelativeTo(kMain.getTopWindow());
}
//}}}
//{{{ getToolsMenuItem, toString
//##################################################################################################
/**
* Creates a new JMenuItem to be displayed in the Tools menu,
* which will allow the user to access function(s) associated
* with this Plugin.
*
* Only one JMenuItem may be returned, but it could be a JMenu
* that contained several functionalities under it.
*
* The Plugin may return null to indicate that it has no
* associated menu item.
*/
public JMenuItem getToolsMenuItem()
{
return new JMenuItem(new ReflectiveAction(this.toString(), null, this, "onOpenMap"));
}
public String toString()
{ return "Electron density maps"; }
//}}}
//{{{ getHelpMenuItem, getHelpAnchor
//##################################################################################################
/**
* Creates a new JMenuItem to be displayed in the Help menu,
* which will allow the user to access help information associated
* with this Plugin.
*
* Only one JMenuItem may be returned, but it could be a JMenu
* that contained several items under it. However,
* Plugins are encouraged to consolidate all documentation
* into one location. The king.HTMLHelp class may be of use here.
*
* The Plugin may return null to indicate that it has no
* associated menu item.
*/
public JMenuItem getHelpMenuItem()
{
return new JMenuItem(new ReflectiveAction(this.toString(), null, this, "onHelp"));
}
public String getHelpAnchor()
{ return "#edmap-plugin"; }
//}}}
//{{{ onOpenMap, askMapFormat
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onOpenMap(ActionEvent ev)
{
if(kMain.getKinemage() == null) return;
try
{
if(kMain.getApplet() != null) openMapURL();
else openMapFile();
}
catch(IOException ex) // includes MalformedURLException
{
JOptionPane.showMessageDialog(kMain.getTopWindow(),
"An I/O error occurred while loading the file:\n"+ex.getMessage(),
"Sorry!", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace(SoftLog.err);
}
catch(IllegalArgumentException ex)
{
JOptionPane.showMessageDialog(kMain.getTopWindow(),
"Wrong map format was chosen, or map is corrupt:\n"+ex.getMessage(),
"Sorry!", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace(SoftLog.err);
}
}
String askMapFormat(String f) // filename or URL
{
Object[] choices = {MAPTYPE_O, MAPTYPE_XPLOR, MAPTYPE_CCP4};
String defaultChoice = MAPTYPE_O;
if(omapFilter.accept(f)) defaultChoice = MAPTYPE_O;
else if(xmapFilter.accept(f)) defaultChoice = MAPTYPE_XPLOR;
else if(ccp4Filter.accept(f)) defaultChoice = MAPTYPE_CCP4;
String choice = (String)JOptionPane.showInputDialog(kMain.getTopWindow(),
"What format is this map in?",
"Choose format", JOptionPane.PLAIN_MESSAGE,
null, choices, defaultChoice);
return choice;
}
//}}}
//{{{ openMapFile
//##################################################################################################
void openMapFile() throws IOException
{
// Create file chooser on demand
if(filechooser == null) makeFileChooser();
if(JFileChooser.APPROVE_OPTION == filechooser.showOpenDialog(kMain.getTopWindow()))
{
File f = filechooser.getSelectedFile();
if(f != null && f.exists())
{
String choice = askMapFormat(f.getName());
CrystalVertexSource map;
if(MAPTYPE_O.equals(choice))
map = new OMapVertexSource(new FileInputStream(f));
else if(MAPTYPE_XPLOR.equals(choice))
map = new XplorVertexSource(new FileInputStream(f));
else if(MAPTYPE_CCP4.equals(choice))
map = new Ccp4VertexSource(new FileInputStream(f));
else throw new IllegalArgumentException("Map type not specified");
EDMapWindow win = new EDMapWindow(parent, map, f.getName());
kCanvas.repaint(); // otherwise we get partial-redraw artifacts
}
}
}
//}}}
//{{{ openMapURL, onUrlCancel, onUrlOk
//##################################################################################################
void openMapURL() throws MalformedURLException, IOException
{
// Create chooser on demand
if(urlchooser == null) makeURLChooser();
//urlchooser.pack(); -- gets too wide when urlField has a long URL in it
urlchooser.setVisible(true);
// execution halts until dialog is closed...
if(urlChooserOK)
{
CrystalVertexSource map;
URL mapURL = new URL(urlField.getText());
InputStream is = new BufferedInputStream(mapURL.openStream());
String choice = askMapFormat(urlField.getText());
if(MAPTYPE_O.equals(choice)) map = new OMapVertexSource(is);
else if(MAPTYPE_XPLOR.equals(choice)) map = new XplorVertexSource(is);
else if(MAPTYPE_CCP4.equals(choice)) map = new Ccp4VertexSource(is);
else throw new IllegalArgumentException("Map type not specified");
EDMapWindow win = new EDMapWindow(parent, map, mapURL.getFile());
kCanvas.repaint(); // otherwise we get partial-redraw artifacts
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onUrlCancel(ActionEvent ev)
{
urlChooserOK = false;
urlchooser.setVisible(false);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onUrlOk(ActionEvent ev)
{
urlChooserOK = true;
urlchooser.setVisible(false);
}
//}}}
//{{{ valueChanged
//##################################################################################################
/* Gets called when a new URL is picked from the list */
public void valueChanged(ListSelectionEvent ev)
{
Object o = urlList.getSelectedValue();
if(o == null) {}
else
{
String name = o.toString();
urlField.setText("http://"+name);
JApplet applet = kMain.getApplet();
if(applet != null)
{
try
{
URL mapURL = new URL(applet.getDocumentBase(), applet.getParameter("edmapBase")+"/"+name);
urlField.setText(mapURL.toString());
}
catch(MalformedURLException ex)
{
SoftLog.err.println(applet.getDocumentBase());
SoftLog.err.println(applet.getParameter("edmapBase"));
SoftLog.err.println(name);
ex.printStackTrace(SoftLog.err);
}
}
}
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/UIText.java 0000644 0000000 0000000 00000014432 11531212674 017003 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
//import java.io.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
/**
* UIText
is the kinemage text manager.
* It takes care of displaying and editing the text.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Sun Jun 9 19:06:25 EDT 2002
*/
public class UIText implements MouseListener
{
//{{{ Static fields
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
JFrame frame;
JTextArea textarea;
JButton popupButton;
Collection mageHypertextListeners = new ArrayList();
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Constructor
*/
public UIText(KingMain kmain)
{
kMain = kmain;
popupButton = new JButton(new ReflectiveAction("Show text", null, this, "onPopupButton"));
frame = new JFrame("Text window");
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setIconImage(kMain.getPrefs().windowIcon);
textarea = new JTextArea();
textarea.setEditable(true);
textarea.setLineWrap(true);
textarea.setWrapStyleWord(true);
textarea.addMouseListener(this);
textarea.setBorder(BorderFactory.createEmptyBorder(6,6,6,6));
//textarea.setFont(new Font("Monospaced", Font.PLAIN, (int)Math.round(12 * kMain.getPrefs().getFloat("fontMagnification"))));
JScrollPane textScroll = new JScrollPane(textarea);
textScroll.setPreferredSize(new Dimension(500,400));
new TextCutCopyPasteMenu(textarea);
this.addHypertextListener(new MageHypertexter(kMain));
frame.getContentPane().add(textScroll, BorderLayout.CENTER);
}
//}}}
//{{{ get/set/appendText()
//##################################################################################################
public String getText()
{ return textarea.getText(); }
public void setText(String txt)
{
textarea.setText(txt);
textarea.setCaretPosition(0); // at the top
}
public void appendText(String txt)
{
txt = getText().concat(txt);
// Keep the text window from moving around too much
int caret = textarea.getCaretPosition();
caret = Math.min(caret, txt.length());
textarea.setText(txt);
textarea.setCaretPosition(caret);
}
//}}}
//{{{ shutdown
//##################################################################################################
/** Initiates shutdown by calling dispose() on the frame. */
public void shutdown()
{
frame.dispose();
}
//}}}
//{{{ cascadeBehind, onPopupButton, getButton
//##################################################################################################
/**
* Positions this window above, left, and behind the specified window.
*/
public void cascadeBehind(Window w)
{
if(w == null) return;
frame.pack();
Point p = w.getLocation();
frame.setLocation(p);
frame.setVisible(true);
p.x += 24;
p.y += 24;
w.setLocation(p);
w.toFront();
w.requestFocus();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onPopupButton(ActionEvent ev)
{
if(!frame.isVisible())
{
frame.pack();
//frame.setLocationRelativeTo(kMain.getTopWindow()); // centers frame
frame.setVisible(true);
}
else
{
frame.toFront();
//frame.requestFocus();
}
}
public JButton getButton() { return popupButton; }
//}}}
//{{{ Mouse listeners (for hypertext)
//##################################################################################################
public void mouseClicked(MouseEvent ev)
{
int where = textarea.viewToModel(ev.getPoint());
//System.err.println("Click occurred at position "+where);
String text = this.getText();
int prevOpen, prevClose, nextOpen, nextClose;
// "where-#" terms below ensure that link is active out through the space between } and *
// Original code used "where" in all four places, cutting the link short.
// Passing a negative start index to (last)IndexOf is the same as passing zero.
prevOpen = text.lastIndexOf("*{", where);
prevClose = text.lastIndexOf("}*", where-2);
nextOpen = text.indexOf("*{", where);
nextClose = text.indexOf("}*", where-1);
//System.err.println("prevs:" + prevOpen + "," + prevClose + "; nexts:" + nextOpen + "," + nextClose);
// Still works if prevClose == -1 Might not be a next hyperlink...
if(prevOpen != -1 && prevOpen > prevClose && nextClose != -1 && (nextClose < nextOpen || nextOpen == -1))
{
String link = text.substring(prevOpen+2, nextClose);
textarea.select(prevOpen, nextClose+2);
//System.err.println("Hit hypertext: '"+link+"'");
for(Iterator iter = mageHypertextListeners.iterator(); iter.hasNext(); )
{
MageHypertextListener listener = (MageHypertextListener) iter.next();
listener.mageHypertextHit(link);
}
}
}
public void mouseEntered(MouseEvent ev) {}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
//}}}
//{{{ add/removeHypertextListener
//##################################################################################################
/** Registers a listener for hypertext events. */
public void addHypertextListener(MageHypertextListener listener)
{
mageHypertextListeners.add(listener);
}
/** Registers a listener for hypertext events. */
public void removeHypertextListener(MageHypertextListener listener)
{
mageHypertextListeners.remove(listener);
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/HTMLHelp.java 0000644 0000000 0000000 00000010473 11531212674 017177 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.html.*;
import driftwood.gui.*;
import driftwood.util.SoftLog;
//}}}
/**
* HTMLHelp
is a simple HTML browser for displaying help information.
*
*
Begun on Wed Jun 26 22:15:35 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class HTMLHelp implements HyperlinkListener
{
//{{{ Static fields
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
JFrame frame;
JEditorPane editpane;
URL homepage;
URL prevpage = null;
LinkedList history;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new help-system window.
*/
public HTMLHelp(KingMain kmain, URL start)
{
kMain = kmain;
homepage = start;
history = new LinkedList();
frame = new JFrame("KiNG Help");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setIconImage(kMain.prefs.windowIcon);
editpane = new JEditorPane();
editpane.addHyperlinkListener(this);
editpane.setEditable(false);
JScrollPane scroll = new JScrollPane(editpane);
scroll.setPreferredSize(new Dimension(600,400));
JToolBar toolbar = new JToolBar();
toolbar.setFloatable(false);
toolbar.add(new JButton(new ReflectiveAction("Back", kMain.prefs.htmlBackIcon, this, "onBack")));
toolbar.addSeparator();
toolbar.add(new JButton(new ReflectiveAction("Home", kMain.prefs.htmlHomeIcon, this, "onHome")));
frame.getContentPane().add(toolbar, BorderLayout.NORTH);
frame.getContentPane().add(scroll, BorderLayout.CENTER);
}
//}}}
//{{{ show/hide
//##################################################################################################
public void show()
{
try
{
editpane.setPage(homepage);
history = new LinkedList(); // clear the history
prevpage = homepage;
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
frame.pack();
frame.setVisible(true);
}
public void hide() { frame.dispose(); }
//}}}
//{{{ hyperlinkUpdate, onBack, onHome
//##################################################################################################
// This was ganked from the JEditorPane documentation.
public void hyperlinkUpdate(HyperlinkEvent ev)
{
if(ev.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
{
if(ev instanceof HTMLFrameHyperlinkEvent)
{
HTMLDocument doc = (HTMLDocument)editpane.getDocument();
doc.processHTMLFrameHyperlinkEvent((HTMLFrameHyperlinkEvent)ev);
}
else
{
try
{
if(prevpage != null) history.addLast(prevpage);
while(history.size() > 100) history.removeFirst();
URL url = ev.getURL();
editpane.setPage(url);
prevpage = url;
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
}
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onBack(ActionEvent ev)
{
if(history.size() < 1) return;
try
{
URL url = (URL)history.removeLast();
editpane.setPage(url);
prevpage = url;
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHome(ActionEvent ev)
{
try
{
history = new LinkedList(); // Clear the history
editpane.setPage(homepage);
prevpage = homepage;
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/ContentPane.java 0000644 0000000 0000000 00000032106 11531212674 020035 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
//import java.io.*;
//import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import driftwood.gui.*;
//}}}
/**
* ContentPane
contains all of the GUI elements,
* except for the menu bar (which is held by the top-level window or applet).
*
*
Begun on Wed Apr 24 11:22:51 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*/
public class ContentPane extends JPanel // implements ...
{
//{{{ Variables
//##################################################################################################
KingMain kMain = null;
JScrollPane buttonScroll = null;
JSplitPane minorSplit = null; // hold buttons and graphics area
JSplitPane majorSplit = null; // hold minor split and zoom/clip sliders
//}}}
//{{{ Constructor
//##################################################################################################
/**
* Does minimal initialization for a main window.
* Call buildGUI() to construct all the GUI elements before calling pack() and setVisible().
* @param kmain the KingMain that owns this window
*/
public ContentPane(KingMain kmain)
{
super(new BorderLayout());
kMain = kmain;
// Set up keystrokes for animations
ActionMap am = this.getActionMap();
InputMap im = this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A , 0), "anim1fwd" );
am.put("anim1fwd", new ReflectiveAction(null, null, this, "onAnimForward" ) );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A , KeyEvent.SHIFT_MASK), "anim1back" );
am.put("anim1back", new ReflectiveAction(null, null, this, "onAnimBackward" ) );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_B , 0), "anim2fwd" );
am.put("anim2fwd", new ReflectiveAction(null, null, this, "onAnim2Forward" ) );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_B , KeyEvent.SHIFT_MASK), "anim2back" );
am.put("anim2back", new ReflectiveAction(null, null, this, "onAnim2Backward" ) );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS , 0), "accum1" );
am.put("accum1", new ReflectiveAction(null, null, this, "onAccumulate" ) );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS , KeyEvent.SHIFT_MASK), "accum2" );
am.put("accum2", new ReflectiveAction(null, null, this, "onAccumulate2" ) );
}
//}}}
//{{{ notifyChange
//##################################################################################################
// Called by KingMain when something happens.
// Shouldn't be called directly under normal circumstances.
static final int REDO_BUTTONS = KingMain.EM_SWITCH | KingMain.EM_CLOSE | KingMain.EM_CLOSEALL | KingMain.EM_EDIT_GROSS;
void notifyChange(int event_mask)
{
// Take care of yourself
if((event_mask & REDO_BUTTONS) != 0)
{
Kinemage kin = kMain.getKinemage();
if(kin != null) setButtons(kin.buildButtons());
else setButtons(Box.createVerticalBox());
}
// Notify children
}
//}}}
//{{{ buildGUI()
//##################################################################################################
/** Defaults to showing both button panel and slider panel */
public void buildGUI() { buildGUI(true, true); }
/**
* Called after the constructor has finished, this starts a cascade that creates all subcomponents and initializes them.
* After calling this, be sure to call pack() and setVisible(true) to make everything appear on screen.
*/
public void buildGUI(boolean useButtons, boolean useSliders)
{
Container content = this;
Component graphicsArea, buttonArea, topArea, bottomArea, totalArea;
// Build major sub-components
graphicsArea = buildGraphicsArea();
buttonArea = buildButtons();
bottomArea = buildBottomArea();
// Build top component -- horizontal splitter
if(useButtons)
{
minorSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, graphicsArea, buttonArea);
minorSplit.setOneTouchExpandable(true);
minorSplit.setResizeWeight(1.0); // gives all extra space to the left side (graphics)
topArea = minorSplit;
}
else
{
minorSplit = null;
topArea = graphicsArea;
}
// Build total GUI -- vertical splitter
if(useSliders)
{
majorSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topArea, bottomArea);
majorSplit.setOneTouchExpandable(true);
majorSplit.setResizeWeight(1.0); // gives all extra space to the top side (graphics)
content.add(majorSplit, BorderLayout.CENTER);
}
else
{
majorSplit = null;
content.add(topArea, BorderLayout.CENTER);
}
}
//}}}
//{{{ buildGraphicsArea, get/setGraphicsComponent
//##################################################################################################
// Assembles the area in which graphics are drawn.
Component buildGraphicsArea()
{
return kMain.getCanvas();
}
/** Sets the component that will occupy KinCanvas's usual space */
public void setGraphicsComponent(Component c)
{
if(minorSplit == null)
{
if(majorSplit == null) this.add(c, BorderLayout.CENTER);
else majorSplit.setTopComponent(c);
}
else minorSplit.setLeftComponent(c);
}
/** Gets the component currently acting as the drawing surface */
public Component getGraphicsComponent()
{
if(minorSplit == null)
{
if(majorSplit == null) return this.getComponents()[0];
else return majorSplit.getTopComponent();
}
else return minorSplit.getLeftComponent();
}
//}}}
//{{{ buildButtons
//##################################################################################################
JComponent buildButtons()
{
// Build the buttons later; create a scrolling panel for them now
buttonScroll = new JScrollPane();
buttonScroll.setPreferredSize(new Dimension(150,200));
// Build the kinemage chooser
JScrollPane chooserScroll = new JScrollPane(kMain.getStable().getChooser());
// Put tabbed panel into another panel along with kin chooser
JPanel overpanel = new JPanel(new BorderLayout());
overpanel.add(chooserScroll, BorderLayout.NORTH);
overpanel.add(buttonScroll, BorderLayout.CENTER);
return overpanel;
}
//}}}
//{{{ buildBottomArea()
//##################################################################################################
// Assembles the area that holds depth clipping, show markers, pickcenter, etc.
Component buildBottomArea()
{
JLabel zoomLabel = new JLabel("Zoom");
JSlider zoomSlider = new JSlider(kMain.getCanvas().getZoomModel());
JLabel clipLabel = new JLabel("Clipping");
JSlider clipSlider = new JSlider(kMain.getCanvas().getClipModel());
JButton hierarchyButton = new JButton(new ReflectiveAction("Show hierarchy", null, this, "onShowHierarchy"));
hierarchyButton.setToolTipText("Show an editable tree view of the kinemage");
GridBagPanel bottomPane = new GridBagPanel();
bottomPane.setBorder( BorderFactory.createEmptyBorder(4,1,2,1) ); //TLBR
// zoom & clip
bottomPane.gbc.insets = new Insets(0, 3, 0, 1); //TLBR
bottomPane.add(zoomLabel, 0, 0);
bottomPane.add(clipLabel, 0, 1);
bottomPane.gbc.insets = new Insets(0, 1, 0, 3); //TLBR
bottomPane.add(zoomSlider, 1, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 1.0, 0.0);
bottomPane.add(clipSlider, 1, 1, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 1.0, 0.0);
// pickcenter and markers
bottomPane.gbc.insets = new Insets(0, 3, 0, 3); //TLBR
bottomPane.gbc.fill = GridBagConstraints.HORIZONTAL;
bottomPane.gbc.weightx = 0.01;
bottomPane.add(kMain.getCanvas().getPickcenterButton(), 2, 0, 1, 1);
bottomPane.add(kMain.getCanvas().getMarkersButton(), 2, 1, 1, 1);
// text & tools
if(kMain.getTextWindow() != null)
{
JButton textButton = kMain.getTextWindow().getButton();
textButton.setToolTipText("Display/edit the textual annotation of this kinemage");
bottomPane.add(textButton, 3, 0, 1, 1);
}
bottomPane.add(hierarchyButton, 3, 1, 1, 1);
return bottomPane;
}
//}}}
//{{{ setButtons()
//##################################################################################################
public void setButtons(Component c)
{
KingPrefs prefs = kMain.getPrefs();
Kinemage kin = kMain.getKinemage();
if(kin == null || prefs == null)
{
buttonScroll.setViewportView(c);
return;
}
TablePane2 cp = new TablePane2();
cp.hfill(true).vfill(true).insets(0).addCell(c,2,1).newRow();
cp.weights(1,0).insets(1).memorize();
if(kin.hasAnimateGroups())
{
JButton backButton = new JButton(new ReflectiveAction(null, prefs.stepBackIcon, this, "onAnimBackward"));
backButton.setToolTipText("Step backward one frame in the main animation");
JButton fwdButton = new JButton(new ReflectiveAction(null, prefs.stepForwardIcon, this, "onAnimForward"));
fwdButton.setToolTipText("Step forward one frame in the main animation");
cp.addCell(cp.strut(0,8),2,1).newRow();
cp.center().addCell(new JLabel("Animate"),2,1).newRow();
cp.right().addCell(backButton).left().addCell(fwdButton).newRow();
}
if(kin.has2AnimateGroups())
{
JButton backButton = new JButton(new ReflectiveAction(null, prefs.stepBackIcon, this, "onAnim2Backward"));
backButton.setToolTipText("Step backward one frame in the secondary animation");
JButton fwdButton = new JButton(new ReflectiveAction(null, prefs.stepForwardIcon, this, "onAnim2Forward"));
fwdButton.setToolTipText("Step forward one frame in the secondary animation");
cp.addCell(cp.strut(0,8),2,1).newRow();
cp.center().addCell(new JLabel("2-Animate"),2,1).newRow();
cp.right().addCell(backButton).left().addCell(fwdButton).newRow();
}
buttonScroll.setViewportView(cp);
// Makes sure that the brushed metal look appears on OS X.
// java.swing.Boxes apparently don't draw their background correctly.
// Aiieee! This just makes it worse. Half stripped, half metal!
//JPanel wrapper = new JPanel(new BorderLayout());
//wrapper.add(c, BorderLayout.CENTER);
//buttonScroll.setViewportView(wrapper);
}
//}}}
//{{{ onAnim(2)Forward, onAnim(2)Backward, onShowHierarchy
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onAnimForward(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null) k.animate(1);
kMain.getCanvas().repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onAnimBackward(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null) k.animate(-1);
kMain.getCanvas().repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onAnim2Forward(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null) k.animate2(1);
kMain.getCanvas().repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onAnim2Backward(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null) k.animate2(-1);
kMain.getCanvas().repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onShowHierarchy(ActionEvent ev)
{
KinTree win = kMain.getKinTree();
if(win != null) win.show();
}
//}}}
//{{{ onAccumulate, onAccumulate2
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onAccumulate(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null) k.accumulate();
kMain.getCanvas().repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onAccumulate2(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null) k.accumulate2();
kMain.getCanvas().repaint();
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/ColorPicker.java 0000644 0000000 0000000 00000023535 11531212674 020041 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
//}}}
/**
* ColorPicker
is a graphical color picker
* for KPaint objects.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Thu Jun 26 11:46:23 EDT 2003
*/
public class ColorPicker extends TablePane implements MouseListener
{
//{{{ Constants
//}}}
//{{{ CLASS: ColorPatch
//##################################################################################################
/** A little patch of color that responds to mouse clicks. */
protected class ColorPatch extends JComponent implements MouseListener
{
KPaint paint;
boolean isSelected = false;
protected ColorPatch(KPaint paint)
{
super();
this.paint = paint;
setMinimumSize(patchSize);
setPreferredSize(patchSize);
setMaximumSize(patchSize);
setToolTipText(paint.toString());
addMouseListener(this);
}
/** Paints our component to the screen */
protected void paintComponent(Graphics g)
{
super.paintComponent(g); // this does nothing b/c we have no UI delegate
Graphics2D g2 = (Graphics2D)g;
Dimension dim = this.getSize();
Paint[] colors = paint.getPaints(backgroundMode);
// First band occupies half height, others divide remainder evenly
int start = 0, height = dim.height/2;
for(int i = KPaint.COLOR_LEVELS-1 ; i >= 0; i--)
{
g2.setPaint(colors[i]);
g2.fillRect(0, start, dim.width, height);
start += height;
height = (dim.height - start) / (i<1 ? 1 : i);
}
if(isSelected)
{
g2.setPaint(highlight);
g2.drawRect(0, 0, dim.width-1, dim.height-1);
}
}
public void mouseClicked(MouseEvent ev) { selectPatch(this); }
public void mouseEntered(MouseEvent ev) {}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
}
//}}}
//{{{ Variable definitions
//##################################################################################################
int backgroundMode;
Dimension patchSize;
Component filler;
SwapBox extraPatchBox;
Color background;
Color highlight;
ColorPatch selectedPatch = null;
/** Map<String, ColorPatch> for setSelection() */
Map patchMap = new HashMap();
Map extraMap = new HashMap();
/** List of listeners for ChangeEvents */
Collection changeListeners = new ArrayList();
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public ColorPicker(int backgroundMode, int patchWidth)
{
super();
this.patchSize = new Dimension(patchWidth, patchWidth);
this.filler = Box.createRigidArea(patchSize);
this.extraPatchBox = new SwapBox(null); // empty for now
this.setBackgroundMode(backgroundMode);
this.setToolTipText("Click empty space to deselect all colors");
this.addMouseListener(this);
addPatch(KPalette.red); addPatch(KPalette.pink); addPatch(KPalette.pinktint); addFiller();
newRow();
addPatch(KPalette.orange); addPatch(KPalette.peach); addPatch(KPalette.peachtint); addFiller();
newRow();
addPatch(KPalette.gold); addFiller(); addFiller(); addFiller();
newRow();
addPatch(KPalette.yellow); addPatch(KPalette.yellow); addPatch(KPalette.yellowtint); addFiller();
newRow();
addPatch(KPalette.lime); addFiller(); addFiller(); addFiller();
newRow();
addPatch(KPalette.green); addPatch(KPalette.sea); addPatch(KPalette.greentint); addFiller();
newRow();
addPatch(KPalette.sea); addFiller(); addFiller(); addPatch(KPalette.white);
newRow();
addPatch(KPalette.cyan); addFiller(); addFiller(); addPatch(KPalette.gray);
newRow();
addPatch(KPalette.sky); addFiller(); addFiller(); addPatch(KPalette.brown);
newRow();
addPatch(KPalette.blue); addPatch(KPalette.sky); addPatch(KPalette.bluetint); addFiller();
newRow();
addPatch(KPalette.purple); addPatch(KPalette.lilac); addPatch(KPalette.lilactint); addFiller();
newRow();
addPatch(KPalette.magenta); addFiller(); addFiller(); addPatch(KPalette.deadwhite);
newRow();
addPatch(KPalette.hotpink); addFiller(); addPatch(KPalette.invisible); addPatch(KPalette.deadblack);
newRow();
insets(0).hfill(true).vfill(true);
addCell(extraPatchBox, 4, 1);
}
//}}}
//{{{ addPatch, addFiller, selectPatch
//##################################################################################################
private void addPatch(KPaint paint)
{
ColorPatch patch = new ColorPatch(paint);
this.addCell(patch);
patchMap.put(paint.toString(), patch);
}
private void addFiller()
{
this.addCell(filler);
}
void selectPatch(ColorPatch newSelection)
{
if(selectedPatch != null)
{
selectedPatch.isSelected = false;
selectedPatch.repaint();
}
selectedPatch = newSelection;
if(selectedPatch != null)
{
selectedPatch.isSelected = true;
selectedPatch.repaint();
}
fireStateChanged();
}
//}}}
//{{{ add/removeChangeListener, fireStateChanged
//##################################################################################################
public void addChangeListener(ChangeListener l)
{
changeListeners.add(l);
}
public void removeChangeListener(ChangeListener l)
{
changeListeners.remove(l);
}
/** Notifies all listeners and repaints this component */
protected void fireStateChanged()
{
ChangeEvent ev = new ChangeEvent(this);
for(Iterator iter = changeListeners.iterator(); iter.hasNext(); )
{
((ChangeListener)iter.next()).stateChanged(ev);
}
}
//}}}
//{{{ get/set{Selection, BackgroundMode}
//##################################################################################################
/** Returns the selected KPaint, or null for none */
public KPaint getSelection()
{
if(selectedPatch == null) return null;
else return selectedPatch.paint;
}
public void setSelection(String color)
{
ColorPatch patch = (ColorPatch)patchMap.get(color);
if(patch == null) patch = (ColorPatch)extraMap.get(color);
selectPatch(patch);
}
public void setSelection(KPaint color)
{
if(color == null) setSelection((String)null);
else setSelection(color.toString());
}
/** Returns one of the KPaint background mode integers. */
public int getBackgroundMode()
{ return backgroundMode; }
public void setBackgroundMode(int mode)
{
this.backgroundMode = mode;
if(backgroundMode == KPaint.BLACK_COLOR)
{
background = KPaint.black;
highlight = KPaint.white;
}
else if(backgroundMode == KPaint.BLACK_MONO)
{
background = KPaint.black;
highlight = KPaint.white;
}
else if(backgroundMode == KPaint.WHITE_COLOR)
{
background = KPaint.white;
highlight = KPaint.black;
}
else if(backgroundMode == KPaint.WHITE_MONO)
{
background = KPaint.white;
highlight = KPaint.black;
}
setOpaque(true);
setBackground(background);
repaint();
}
//}}}
//{{{ setExtras
//##################################################################################################
/**
* Allows this component to display extra colors, e.g. from colorsets.
* Usually fed the output of Kinemage.getNewPaintMap().values().
* @param kPaints a Collection<KPaint>; may be null.
*/
public void setExtras(Collection kPaints)
{
extraPatchBox.setTarget(null);
extraMap.clear();
if(kPaints == null) return;
int i = 0;
TablePane tp = new TablePane();
tp.setOpaque(false); // lets black/white show through
for(Iterator iter = kPaints.iterator(); iter.hasNext(); i++)
{
KPaint paint = (KPaint)iter.next();
ColorPatch patch = new ColorPatch(paint);
tp.addCell(patch);
extraMap.put(paint.toString(), patch);
if(++i % 4 == 0) tp.newRow();
}
extraPatchBox.setTarget(tp);
}
//}}}
//{{{ mouse{Clicked, Entered, Exited, Pressed, Released}
//##################################################################################################
public void mouseClicked(MouseEvent ev) { selectPatch(null); }
public void mouseEntered(MouseEvent ev) {}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/ReflectiveRunnable.java 0000644 0000000 0000000 00000003712 11531212674 021377 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
//import java.awt.*;
//import java.io.*;
import java.lang.reflect.*;
//import java.text.*;
//import java.util.*;
//import javax.swing.*;
import driftwood.util.SoftLog;
//}}}
/**
* ReflectiveRunnable
uses the Reflection API to redirect calls to run() to any method in any class.
* It operates much like ReflectiveAction
.
* This is also known (apparently) as a trampoline, because it bounces you from one method to another.
* I got the idea and most of the implementation from http://java.sun.com/docs/books/performance/
*
*
Begun on Wed Jun 12 09:33:00 EDT 2002
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*/
public class ReflectiveRunnable implements Runnable
{
//{{{ Static fields
//}}}
//{{{ Variable definitions
//##################################################################################################
Object targetObject;
String methodName;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a run()-redirector.
* @param target the object to receive the function call
* @param method the name of the method to call; method must be declared as public void some_method().
*/
public ReflectiveRunnable(Object target, String method)
{
targetObject = target;
methodName = method;
}
//}}}
//{{{ run()
//##################################################################################################
public void run()
{
try
{
Class[] formalParams = { };
Method m = targetObject.getClass().getMethod(methodName, formalParams);
Object[] params = { };
m.invoke(targetObject, params);
}
catch(Exception ex) { ex.printStackTrace(SoftLog.err); }
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/MainWindow.java 0000644 0000000 0000000 00000002626 11531212674 017677 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
//import java.io.*;
//import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import driftwood.gui.*;
//}}}
/**
* MainWindow
is a top-level holder for a ContentPane and a menu bar.
* Other than that, it doesn't do much!
*
*
Begun on Wed Apr 24 11:22:51 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*/
public class MainWindow extends JFrame // implements ...
{
//{{{ Variables
//##################################################################################################
//}}}
//{{{ Constructor
//##################################################################################################
/**
* Does minimal initialization for a main window.
* @param kmain the KingMain that owns this window
*/
public MainWindow(KingMain kmain)
{
super("KiNG "+kmain.getPrefs().getString("version"));
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setIconImage(kmain.prefs.windowIcon);
}
//}}}
//{{{ shutdown
//##################################################################################################
/** Initiates shutdown by calling dispose() on the window. */
public void shutdown()
{
this.dispose();
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/KinLoadListener.java 0000644 0000000 0000000 00000002221 11531212674 020641 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* KinLoadListener
is an interface for monitoring
* the progress of a kinemage that's being loaded in the
* background. All these methods are called from the
* Swing event-handling thread.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Fri Apr 11 10:07:14 EDT 2003
*/
public interface KinLoadListener //extends ... implements ...
{
/**
* Messaged periodically as the parser reads the file.
*/
public void updateProgress(long charsRead);
/**
* Messaged if anything is thrown during the loading process.
* This generally means loadingComplete() won't be called.
*/
public void loadingException(Throwable t);
/**
* Messaged if and when loading finished successfully.
*/
public void loadingComplete(KinfileParser parser);
}//class
king-2.21.120420/king/1.x_src/king/core/ 0000755 0000000 0000000 00000000000 11744310054 015677 5 ustar root root king-2.21.120420/king/1.x_src/king/core/AGE.java 0000644 0000000 0000000 00000024357 11531212670 017150 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.tree.*;
import driftwood.gui.*;
import driftwood.r3.*;
//}}}
/**
* AGE
(Abstract Grouping Element) is the basis for all groups, subgroups, lists, kinemages, etc.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 10:50:36 EDT 2002
*/
abstract public class AGE extends AHEImpl implements MutableTreeNode
{
//{{{ Variable definitions
//##################################################################################################
static final Border cboxBorder = BorderFactory.createEmptyBorder(1,2,1,2);
public java.util.List children = null;
public ArrayList masters = null;
boolean on = true;
JCheckBox cbox = null;
boolean nobutton = false;
boolean dominant = false;
boolean recessiveon = false;
boolean lens = false;
//}}}
//{{{ clone
//##################################################################################################
/**
* Creates a deep copy of this AGE and all its children,
* including make full copies of all the points.
* Not all AGEs implement Cloneable, so this operation could fail.
*/
public Object clone() throws CloneNotSupportedException
{ return clone(true); }
/**
* Creates a copy of this AGE and all its children.
* Not all AGEs implement Cloneable, so this operation could fail.
* @param clonePoints whether to clone even the individual points,
* or whether we should use instance= at the list level instead.
*/
public Object clone(boolean clonePoints) throws CloneNotSupportedException
{ return super.clone(); }
//}}}
//{{{ setName, iterator
//##################################################################################################
/** Sets the name of this element */
public void setName(String nm)
{
super.setName(nm);
cbox = new JCheckBox(new ReflectiveAction(getName(), null, this, "cboxHit"));
cbox.setAlignmentX(Component.LEFT_ALIGNMENT);
cbox.setBorder(cboxBorder);
cbox.setSelected(on);
}
/** Returns an iterator over the children of this element. All children will be AHE's. */
public ListIterator iterator()
{ return children.listIterator(); }
//}}}
//{{{ is/setOn, (set)hasButton, is/setDominant, is/setRecessiveOn, is/setLens
//##################################################################################################
/** Indicates whether this element will paint itself, given the chance */
public boolean isOn()
{ return on; }
/** Sets the painting status of this element */
public void setOn(boolean paint)
{
on = paint;
cbox.setSelected(on);
}
/** Indicates whether this element would display a button, given the chance */
public boolean hasButton()
{ return !nobutton; }
/** Sets whether this element would display a button, given the chance */
public void setHasButton(boolean b)
{ nobutton = !b; }
/** Indicates whether this element supresses buttons of elements below it */
public boolean isDominant()
{ return dominant; }
/** Sets whether this element supresses buttons of elements below it */
public void setDominant(boolean b)
{ dominant = b; }
/** Indicates whether this element supresses buttons of elements below it WHEN OFF */
public boolean isRecessiveOn()
{ return recessiveon; }
/** Sets whether this element supresses buttons of elements below it WHEN OFF */
public void setRecessiveOn(boolean b)
{ recessiveon = b; }
/**
* Indicates whether or not the points under this element
* should be hidden if they are more than a certain distance
* from the current center of viewing.
* The name comes from the visualization community, where
* this function is likened to a magnifying glass.
*/
public boolean isLens()
{ return lens; }
public void setLens(boolean b)
{ lens = b; }
//}}}
//{{{ cboxHit(), notifyCboxHit(), buildButtons()
//##################################################################################################
/** Called when the associated checkbox is turned on/off */
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void cboxHit(ActionEvent ev)
{
on = cbox.isSelected();
notifyCboxHit();
}
/** Propagates notice upward that a checkbox was turned on/off */
public void notifyCboxHit()
{
getOwner().notifyCboxHit();
}
/** Builds a grouping of Mage-style on/off buttons in the specified container. */
protected void buildButtons(Container cont)
{
if(hasButton()) cont.add(cbox);
if(!isDominant())
{
AlignBox subbox = new AlignBox(BoxLayout.Y_AXIS);
subbox.setAlignmentX(Component.LEFT_ALIGNMENT);
for(Iterator iter = children.iterator(); iter.hasNext(); )
{ ((AGE)iter.next()).buildButtons(subbox); }
IndentBox ibox;
if(isRecessiveOn()) ibox = new FoldingBox(cbox, subbox);
else ibox = new IndentBox(subbox);
ibox.setIndent(8);
cont.add(ibox);
}
}
//}}}
//{{{ calcBoundingBox() and calcRadiusSq()
//##################################################################################################
/**
* Gets a bounding box for the current model.
* @param bound the first 6 elements get set to { minX, minY, minZ, maxX, maxY, maxZ }.
* Should be called with { +inf, +inf, +inf, -inf, -inf, -inf }
*/
public void calcBoundingBox(float[] bound)
{
Iterator iter = children.iterator();
while(iter.hasNext()) ((AHE)iter.next()).calcBoundingBox(bound);
}
/**
* Gets the square of the radius of this model from the specified center.
* @param center an array with the x, y, and z coordinates of the center
* @return the square of the radius of this element, centered at center
*/
public float calcRadiusSq(float[] center)
{
float max = 0f;
Iterator iter = children.iterator();
while(iter.hasNext()) max = Math.max(max, ((AHE)iter.next()).calcRadiusSq(center));
return max;
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
// If the button is off, this will never be rendered
if(!isOn()) return;
// Not using iterators speeds this up by a few tens of ms
int i, end_i;
end_i = children.size();
for(i = 0; i < end_i; i++) ((AHE)children.get(i)).signalTransform(engine, xform);
}
//}}}
//{{{ addMaster, removeMaster, hasMaster, masterIterator
//##################################################################################################
/** Makes the named master control this AGE */
public void addMaster(String masterName)
{
if(masters == null) masters = new ArrayList(5);
if(!masters.contains(masterName))
{
masters.add(masterName);
}
}
/** Stops the named master from controlling this AGE. No action if it wasn't ever added. */
public void removeMaster(String masterName)
{
if(masters == null) return;
int i;
if((i = masters.lastIndexOf(masterName)) != -1)
{
masters.remove(i);
}
}
/** Returns true iff the named master controls this AGE */
public boolean hasMaster(String masterName)
{
if(masters == null) return false;
else return masters.contains(masterName);
}
/** Returns an iterator over this AGE's masters (as Strings), or null if there are none. */
public Iterator masterIterator()
{
if(masters == null) return null;
else return masters.iterator();
}
//}}}
//{{{ MutableTreeNode functions
//##################################################################################################
// Required to be a TreeNode
public Enumeration children() { return Collections.enumeration(children); }
public boolean getAllowsChildren() { return true; }
public TreeNode getChildAt(int childIndex) { return (TreeNode)children.get(childIndex); }
public int getChildCount() { return children.size(); }
public int getIndex(TreeNode node) { return children.indexOf(node); }
public TreeNode getParent() { return getOwner(); }
public boolean isLeaf() { return false; }
// Required to be a MutableTreeNode
// public void insert(MutableTreeNode child, int index)
public void remove(int index) { children.remove(index); }
public void remove(MutableTreeNode node) { children.remove(node); }
public void removeFromParent() { getOwner().remove(this); }
public void setParent(MutableTreeNode newParent) { setOwner((AGE)newParent); }
public void setUserObject(Object obj) {}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KList.java 0000644 0000000 0000000 00000026113 11531212670 017572 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.tree.*;
import driftwood.r3.*;
//}}}
/**
* KList
implements the concept of a list in a kinemage.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 12:37:31 EDT 2002
*/
public class KList extends AGE implements Cloneable
{
//{{{ Constants
public static final String UNKNOWN = "";
public static final String VECTOR = "vector";
public static final String DOT = "dot";
public static final String MARK = "mark";
public static final String LABEL = "label";
public static final String TRIANGLE = "triangle";
public static final String RIBBON = "ribbon";
public static final String RING = "ring";
public static final String BALL = "ball";
public static final String SPHERE = "sphere";
public static final String ARROW = "arrow";
public static final int NOHILITE = 0x00000001; // no highlight on balls
//}}}
//{{{ Variable definitions
//##################################################################################################
KSubgroup parent = null;
KList instance = null; // the list that this one is an instance= {xxx} of, or null
public String type = UNKNOWN; // type of object represented by this list
public KPaint color = KPalette.defaultColor;
public int alpha = 255; // 255 = opaque, 0 = fully transparent
public float radius = 0.2f; // seems to be default in Mage; also used for arrow tine length (radius=)
public int width = 2;
public int flags = 0; // nohighlight for balls, style for markers, etc
Object clipMode = null; // null for default, else some object key
int dimension = 3; // for high-dimensional kinemages
// Parameters used for arrowlists; see ArrowPoint for explanation
// of tine PERPendicular and PARallel components.
float angle = 20f;
float tinePerp = (float)(radius * Math.sin(Math.toRadians(angle)));
float tinePar = (float)(radius * Math.cos(Math.toRadians(angle)));
//}}}
//{{{ Constructor(s)
//##################################################################################################
/** Constructor */
public KList()
{
children = new ArrayList(20);
setName(null);
}
/** Constructor */
public KList(KSubgroup owner, String nm)
{
children = new ArrayList(20);
setOwner(owner);
setName(nm);
}
//}}}
//{{{ clone
//##################################################################################################
/**
* Creates a copy of this group and all its children.
* @param clonePoints whether to clone even the individual points,
* or whether we should use instance= at the list level instead.
*/
public Object clone(boolean clonePoints)
{
try
{
KList x = (KList) super.clone(clonePoints);
x.setName( x.getName() ); // tricks it into creating a new JCheckBox object
x.children = new ArrayList();
if(clonePoints)
{
// Deep copy of children from original source
KList orig = this;
while(orig.getInstance() != null) orig = orig.getInstance();
KPoint prev = null;
for(Iterator iter = orig.children.iterator(); iter.hasNext(); )
{
KPoint child = (KPoint) iter.next();
KPoint clone = (KPoint) child.clone();
clone.setOwner(x);
x.add(clone);
// Everything has been deep copied; we just need
// to correct the linked-list pointers for
// VectorPoints and TrianglePoints.
if(clone.getPrev() != null)
clone.setPrev(prev);
prev = clone;
}
}
else // we'll use instance= to fake it!
{
if(this.getInstance() == null)
x.setInstance(this);
else
x.setInstance(this.getInstance());
}
// Semi-deep copy of masters, which just contains Strings
if(this.masters != null) x.masters = new ArrayList(this.masters);
return x;
}
catch(CloneNotSupportedException ex)
{ throw new Error("Clone failed in cloneable object"); }
}
//}}}
//{{{ get/setOwner, get/setInstance
//##################################################################################################
/** Determines the owner (parent) of this element */
public AGE getOwner()
{ return parent; }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{
parent = (KSubgroup)owner;
}
/** Sets which list this one is an instance of, or null for none. */
public void setInstance(KList inst)
{ this.instance = inst; }
/** Gets which list this one is an instance of, or null for none. */
public KList getInstance()
{ return this.instance; }
//}}}
//{{{ get/set{Type, Color, Width, Radius, Angle, Style, ClipMode}
//##################################################################################################
/** Determines the type of points held by this list */
public String getType()
{ return type; }
/** Establishes the type of points held by this list */
public void setType(String t)
{
type = t;
}
/** Determines the default color of points held by this list */
public KPaint getColor()
{ return color; }
/** Establishes the default color of points held by this list */
public void setColor(KPaint c)
{ color = c; }
/** Determines the default width of points held by this list */
public int getWidth()
{ return width; }
/** Establishes the default width of points held by this list */
public void setWidth(int w)
{
if(w > 7) width = 7;
else if(w < 1) width = 1;
else width = w;
}
public float getRadius()
{ return radius; }
public void setRadius(float r)
{
radius = r;
tinePerp = (float)(radius * Math.sin(Math.toRadians(angle)));
tinePar = (float)(radius * Math.cos(Math.toRadians(angle)));
}
/** For use with ArrowPoint */
public float getAngle()
{ return angle; }
public void setAngle(float a)
{
angle = a;
tinePerp = (float)(radius * Math.sin(Math.toRadians(angle)));
tinePar = (float)(radius * Math.cos(Math.toRadians(angle)));
}
/** For use with MarkerPoint */
public int getStyle()
{ return flags; }
public void setStyle(int s)
{ flags = s; }
/** Gets the clipping mode key for this list. Usually null. See Engine.chooseClipMode(). */
public Object getClipMode()
{ return clipMode; }
/** Sets the clipping mode for this list. */
public void setClipMode(Object key)
{ this.clipMode = key; }
/** Returns the nominal number of coordinates per point in this list. */
public int getDimension() { return this.dimension; }
/** Sets the nominal number of coordinates per point in this list. */
public void setDimension(int d) { this.dimension = d; }
//}}}
//{{{ add, clear
//##################################################################################################
/** Adds a child to this element */
public void add(KPoint child)
{ children.add(child); }
/** Removes all children from this element */
public void clear()
{ children.clear(); }
//}}}
//{{{ buildButtons()
//##################################################################################################
protected void buildButtons(Container cont)
{
if(hasButton()) cont.add(cbox);
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
// If the button is off, this will never be rendered
if(!isOn()) return;
int i, end_i;
if(this.clipMode != null) engine.chooseClipMode(this.clipMode); // set alt clipping
// If we're an instance of someone else, transform those points too
if(instance != null)
{
engine.setActingParent(this);
end_i = instance.children.size();
for(i = 0; i < end_i; i++) ((KPoint)instance.children.get(i)).signalTransform(engine, xform, engine.zoom3D);
}
// Not using iterators speeds this up by a few tens of ms
engine.setActingParent(null);
end_i = children.size();
for(i = 0; i < end_i; i++) ((KPoint)children.get(i)).signalTransform(engine, xform, engine.zoom3D);
if(this.clipMode != null) engine.chooseClipMode(null); // reset to default
}
//}}}
//{{{ MutableTreeNode functions
//##################################################################################################
// Required to be a TreeNode
public Enumeration children() { return null; }
public boolean getAllowsChildren() { return false; }
public TreeNode getChildAt(int childIndex) { return null; }
/** Returns 0 for JTree so points won't be visible; not equal to children.size(). */
public int getChildCount() { return 0; }
public int getIndex(TreeNode node) { return 0; }
public TreeNode getParent() { return getOwner(); }
public boolean isLeaf() { return true; }
// Required to be a MutableTreeNode
public void insert(MutableTreeNode child, int index) {}
public void remove(int index) {}
public void remove(MutableTreeNode node) {}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/MarkerPoint.java 0000644 0000000 0000000 00000007343 11531212670 021003 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.io.*;
//import java.text.*;
//import java.util.*;
//import javax.swing.*;
//}}}
/**
* MarkerPoint
is a "screen-oriented displayable" that can take on many different looks.
* It servers as a marker for picked points and may come in list form, e.g. for graphs.
*
*
Begun on Sun Jun 23 15:33:28 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class MarkerPoint extends AbstractPoint // implements ...
{
//{{{ Static fields
public static final int CROSS_S = 0x00000001;
public static final int CROSS_M = 0x00000002;
public static final int CROSS_L = 0x00000004;
public static final int CROSS_2 = 0x00000008;
public static final int X_S = 0x00000010;
public static final int X_M = 0x00000020;
public static final int X_L = 0x00000040;
public static final int X_2 = 0x00000080;
public static final int SQUARE_S = 0x00000100;
public static final int SQUARE_M = 0x00000200;
public static final int SQUARE_L = 0x00000400;
public static final int BOX_S = 0x00001000;
public static final int BOX_M = 0x00002000;
public static final int BOX_L = 0x00004000;
public static final int RING_S = 0x00010000;
public static final int RING_M = 0x00020000;
public static final int RING_L = 0x00040000;
public static final int DISC_S = 0x00100000;
public static final int DISC_M = 0x00200000;
public static final int DISC_L = 0x00400000;
//}}}
//{{{ Variable definitions
//##################################################################################################
int style = 0;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new data point displayed as some type of marker.
*
* @param list the list that contains this point
* @param label the pointID of this point
*/
public MarkerPoint(KList list, String label)
{
super(list, label);
}
/** Quick way to follow a point -- creates an unpickable marker named "marker" */
public MarkerPoint(KPoint p, KPaint color, int style_mask)
{
super(null, "marker");
setColor(color);
setStyle(style_mask);
setUnpickable(true);
x0 = (float)p.getX();
y0 = (float)p.getY();
z0 = (float)p.getZ();
}
//}}}
//{{{ get/setStyle()
//##################################################################################################
/** Retrieves the style code for this marker */
public int getStyle() { return style; }
/** Sets the style for this marker. Use a Boolean OR of fields defined in this class. */
public void setStyle(int s) { style = s; }
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
Paint paint = maincolor.getPaint(engine.backgroundMode, engine.colorCue);
int width = engine.markerSize;
// Point style dominants over list style
int paintStyle = 0;
if(this.getStyle() != 0) paintStyle = this.getStyle();
else if(parent != null && parent.getStyle() != 0) paintStyle = parent.getStyle();
engine.painter.paintMarker(paint, x, y, z, width, paintStyle);
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/Painter.java 0000644 0000000 0000000 00000004053 11531212670 020145 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* Painter
is a standard interface for classes that are capable of
* rendering transformed KPoints as 2-D images (usually on the screen).
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Fri May 21 19:11:16 EDT 2004
*/
public interface Painter //extends ... implements ...
{
public void paintBall(Paint paint, double x, double y, double z, double r, boolean showHighlight);
public void paintDot(Paint paint, double x, double y, double z, int width);
public void paintLabel(Paint paint, String label, double x, double y, double z);
public void paintMarker(Paint paint, double x, double y, double z, int width, int paintStyle);
public void paintSphereDisk(Paint paint, double x, double y, double z, double r);
public void paintTriangle(Paint paint,
double x1, double y1, double z1,
double x2, double y2, double z2,
double x3, double y3, double z3);
public void paintVector(Paint paint, int width, int widthCue,
double x1, double y1, double z1,
double x2, double y2, double z2);
// Used by the auger tool for its targeting circle
/** x,y,z is CENTER, not edge like it is for Java AWT functions */
public void drawOval(Paint paint, double x, double y, double z, double width, double height);
public void drawOval(Paint paint, int linewidth, int widthCue, double x, double y, double z, double width, double height);
public void setFont(Font f);
public int getLabelWidth(String s);
public int getLabelAscent(String s);
public int getLabelDescent(String s);
public void setViewport(int x, int y, int width, int height);
public void clearCanvas(Color color); // setViewport() must be called first!
}//class
king-2.21.120420/king/1.x_src/king/core/VectorPoint.java 0000644 0000000 0000000 00000033040 11531212670 021015 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* VectorPoint
represents the endpoint of a line.
*
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*
Begun on Fri Apr 26 16:46:09 EDT 2002
*/
public class VectorPoint extends AbstractPoint // implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
VectorPoint from = null;
int width = 0; // width of this line (0 => use parent.width)
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a new data point representing one end of a line.
*
* @param list the list that contains this point
* @param label the pointID of this point
* @param start where this line is drawn from, or null if it's the starting point
*/
public VectorPoint(KList list, String label, VectorPoint start)
{
super(list, label);
setPrev(start);
}
//}}}
//{{{ get/setPrev, isBreak, get/setWidth
//##################################################################################################
/**
* Sets the point that precedes this one.
* This matters to "chainable" points, like vectors and triangles.
* For other points, it does nothing.
* @param pt the point preceding this one in seqence
*/
public void setPrev(KPoint pt)
{
super.setPrev(pt);
from = (VectorPoint)pt;
}
/**
* Gets the point preceding this one in the chain.
* @return the preceding point, or null if (a) this is a break in the chain or (b) this is not a chainable point type.
*/
public KPoint getPrev()
{ return from; }
/**
* True iff this is a chainable point type (e.g. vector, triangle) AND there is a chain break.
*/
public boolean isBreak()
{ return (from == null); }
/** Gets the line width of this point, if applicable */
public int getWidth()
{ return width; }
/** Sets the line width of this point */
public void setWidth(int w)
{
if(w > 7) width = 7;
else if(w < 0) width = 0;
else width = w;
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
// Don't call super.signalTransform() b/c we do it all here
xform.transform(this, engine.work1);
setDrawXYZ(engine.work1);
// This only works because starting points are listed before ending points
// in a kinemage, thus, from has already been transformed when we get here!
// The idea is to add points based on the midpoint of the *visible* range.
if(from != null)
{
if(from.z < z && from.z <= engine.clipFront && z >= engine.clipBack)
{
engine.addPaintable(this,
(Math.max(from.z, engine.clipBack)+Math.min(z, engine.clipFront)) / 2.0);
}
else if(from.z >= engine.clipBack && z <= engine.clipFront) // && from.z >= z
{
engine.addPaintable(this,
(Math.max(z, engine.clipBack)+Math.min(from.z, engine.clipFront)) / 2.0);
}
// else don't paint
}
else engine.addPaintable(this, z); // won't be painted, but will be pickable
}
//}}}
//{{{ isPickedBy
//##################################################################################################
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{
if(objPick && from != null)
{
VectorPoint A = this, B = from;
// first check: bounding box
if(xx > (Math.min(A.x,B.x) - radius) && xx < (Math.max(A.x,B.x)+radius)
&& yy > (Math.min(A.y,B.y) - radius) && yy < (Math.max(A.y,B.y)+radius))
{
// line as ax + by + d = 0, like a plane
float a = B.y - A.y, b = A.x - B.x;
double num = a*xx + b*yy - (a*A.x + b*A.y); // parenthesized term is -d
double d2 = (num*num) / (a*a + b*b); // square of distance to the line
//System.err.println("x = "+xx+" : "+Math.min(A.x,B.x)+" - "+Math.max(A.x,B.x));
//System.err.println("y = "+yy+" : "+Math.min(A.y,B.y)+" - "+Math.max(A.y,B.y));
//System.err.println("a = "+a+"; b = "+b+"; d = "+(-(a*A.x + b*A.y)));
//System.err.println("D^2 = "+d2);
// Always return the "line to" point, so that color changes work as expected
if(d2 < radius*radius) return this;
/*{
float dx, dy, dA, dB;
dx = xx - A.x; dy = yy - A.y; dA = dx*dx + dy*dy;
dx = xx - B.x; dy = yy - B.y; dB = dx*dx + dy*dy;
if(dA <= dB) return A;
else return B;
}*/
}
}
// Not else {...} b/c this can be true for line ends even outside the bounding box:
return super.isPickedBy(xx, yy, radius, objPick);
}
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
//if(from == null || equals(from)) return;
if(from == null || (x0 == from.x0 && y0 == from.y0 && z0 == from.z0)) return;
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
// [IWD, 4 May 2005]
// For Mage/Prekin, it's enough for EITHER end of the line to be off to
// not draw it. The line below could be replaced with a custom pmHit()
// that ORs this.pm_mask with from.pm_mask before deciding on a hit.
// That would be faster (precomputed) but seems riskier at the moment...
//
// Oops, the real problem is the FROM side not being marked with a pointmaster,
// which means... what? How does this end up being a problem again?
//
// if(from.getDrawingColor(engine).isInvisible()) return;
//Paint paint = maincolor.getPaint(engine.backgroundMode, engine.colorCue);
int alpha = (parent == null ? 255 : parent.alpha);
Paint paint = maincolor.getPaint(engine.backgroundMode, 1, engine.colorCue, alpha);
// If we REALLY wanted to clip line segments to the visible volume, we
// could use 6 planes defining a box / truncated pyramid.
// See ArrowPoint for ideas on Cohen-Sutherland clipping.
// To intersect a line with a plane, from Comp.Graphics.Algorithms FAQ 5:
// If the plane is defined as:
// a*x + b*y + c*z + d = 0
// and the line is defined as:
// x = x1 + (x2 - x1)*t = x1 + i*t
// y = y1 + (y2 - y1)*t = y1 + j*t
// z = z1 + (z2 - z1)*t = z1 + k*t
// Then just substitute these into the plane equation. You end up with:
// t = - (a*x1 + b*y1 + c*z1 + d)/(a*i + b*j + c*k)
// When the denominator is zero, the line is contained in the plane if
// the numerator is also zero (the point at t=0 satisfies the plane
// equation), otherwise the line is parallel to the plane.
//{{{ Determine who's in back and who's in front.
double xb, yb, zb, shortenb, xf, yf, zf, shortenf; // Back and Front
boolean fromIsFront; // are the "f" (front) points this or this.from?
if(from.z < z)
{
fromIsFront = false;
xb = from.x;
yb = from.y;
zb = from.z;
shortenb = engine.getShortening(from);
xf = x;
yf = y;
zf = z;
shortenf = engine.getShortening(this);
}
else // from.z >= z
{
fromIsFront = true;
xf = from.x;
yf = from.y;
zf = from.z;
shortenf = engine.getShortening(from);
xb = x;
yb = y;
zb = z;
shortenb = engine.getShortening(this);
}
//}}} Determine who's in back and who's in front.
//{{{ Shorten to fit in clipping plane, outside of balls
// If line ends extend outside clipping area, calc. its intersection w/ clipping plane
// If a ball resides at one end point, shorten the line by the radius of the ball
double dz, dxdz, dydz, dzb, dzf, sx, sy, sz, s;
dz = zf - zb;
dxdz = (xf - xb)/dz; // == (dx/dz)
dydz = (yf - yb)/dz; // == (dy/dz)
dzb = engine.clipBack - zb;
dzf = engine.clipFront - zf;
// Clipping or shortening for back point.
if(shortenb > 0)
{
s = Math.sqrt(shortenb*shortenb / ((dxdz*dxdz + dydz*dydz + 1)*dz*dz));
sz = s*dz;
sx = sz*dxdz;
sy = sz*dydz;
if(sz > dzb)
{
xb += sx;
yb += sy;
zb += sz;
}
else if(zb < engine.clipBack)
{
xb = xb + dxdz*dzb;
yb = yb + dydz*dzb;
zb = engine.clipBack;
}
}
else if(zb < engine.clipBack)
{
xb = xb + dxdz*dzb;
yb = yb + dydz*dzb;
zb = engine.clipBack;
}
// Clipping or shortening for front point.
if(shortenf > 0)
{
s = Math.sqrt(shortenf*shortenf / ((dxdz*dxdz + dydz*dydz + 1)*dz*dz));
sz = s*dz;
sx = sz*dxdz;
sy = sz*dydz;
if(sz > -dzf)
{
xf -= sx;
yf -= sy;
zf -= sz;
}
else if(zf > engine.clipFront)
{
xf = xf + dxdz*dzf;
yf = yf + dydz*dzf;
zf = engine.clipFront;
}
}
else if(zf > engine.clipFront)
{
xf = xf + dxdz*dzf;
yf = yf + dydz*dzf;
zf = engine.clipFront;
}
//}}} Shorten to fit in clipping plane, outside of balls
//engine.painter.paintVector(paint, calcLineWidth(engine), engine.widthCue,
// xb, yb, zb, xf, yf, zf);
if(fromIsFront) paintStandard2(engine, paint, xf, yf, zf, xb, yb, zb);
else paintStandard2(engine, paint, xb, yb, zb, xf, yf, zf);
}
//}}}
//{{{ paintStandard2
//##################################################################################################
/**
* This function exists solely for the convenience of ArrowPoints;
* a good JIT will optimize it away for VectorPoints.
* Coordinates are already transformed, perspective corrected, and clipped by Z planes.
* They have NOT been clipped to the drawing area yet.
*/
void paintStandard2(Engine engine, Paint paint, double fromX, double fromY, double fromZ, double toX, double toY, double toZ)
{
int lineWidth = calcLineWidth(engine);
engine.painter.paintVector(paint, lineWidth, engine.widthCue,
fromX, fromY, fromZ, toX, toY, toZ);
}
//}}}
//{{{ calcLineWidth
//##################################################################################################
// Vector way of finding the right line width to use, given the settings in the engine
int calcLineWidth(Engine engine)
{
if(engine.thinLines) return 1;
int wid = 2;
if(this.width > 0) wid = this.width;
else if(parent != null) wid = parent.width;
return wid;
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/AbstractPoint.java 0000644 0000000 0000000 00000053251 11531212670 021324 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.data.TinyMap;
import driftwood.r3.*;
//}}}
/**
* AbstractPoint
is a generic, non-instantiable representation of a 'point' in a kinemage.
* This class and its subclasses contain the code for drawing all the different graphics primitives in Mage.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 12:57:57 EDT 2002
*/
abstract public class AbstractPoint extends AHEImpl implements KPoint
{
//{{{ Constants
// Bit allocation for 'multi':
// kngpt points future tinymap
// skkkkkkkppppppppffffffffmmmmmmmm
/** Isolates all the bits used by tinymap */
public static final int TINYMAP_AND = 0xff;
/** tinymap keys, 0 - 7 */
public static final int ASPECTS_KEY = (1<<0);
public static final int COMMENT_KEY = (1<<1);
public static final int COORDS_KEY = (1<<2); // for kins with >3 dimensions
/** If this bit is set, the point is 'live' and should be painted */
public static final int ON_BIT = 0x40000000;
/** If this bit is set, the point will not be picked by a mouse click */
public static final int UNPICKABLE = 0x20000000;
/** Used by e.g. TrianglePoints to tell whose normal to in lighting effects */
public static final int SEQ_EVEN_BIT = 0x10000000;
/** A flag used by Mage only; point is visible but not written to PDB output. */
public static final int GHOST_BIT = 0x08000000;
//}}}
//{{{ Variable definitions
//##################################################################################################
float x0 = 0f, y0 = 0f, z0 = 0f; // permanent coords
float x = 0f, y = 0f, z = 0f; // transformed coords
KList parent = null; // list that contains this point
Object[] tmValues = null; // holds (ASPECTS), , etc.
int pm_mask = 0; // bit flags for pointmasters
/** Color this point is drawn in; null means take from list */
KPaint color = null;
/** higher bits are used as flags */
public int multi = 0 | ON_BIT;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public AbstractPoint()
{
}
/**
* Constructor
*/
public AbstractPoint(KList owner, String nm)
{
setOwner(owner);
setName(nm);
}
//}}}
//{{{ clone
//##################################################################################################
public Object clone()
{
try { return super.clone(); }
catch(CloneNotSupportedException ex)
{ throw new Error("Clone failed in cloneable object"); }
}
//}}}
//{{{ get/setOrigX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getX(). */
public float getOrigX()
{ return x0; }
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getY(). */
public float getOrigY()
{ return y0; }
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getZ). */
public float getOrigZ()
{ return z0; }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setX(). */
public void setOrigX(double xx) { x0 = (float)xx; }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setY(). */
public void setOrigY(double yy) { y0 = (float)yy; }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setZ(). */
public void setOrigZ(double zz) { z0 = (float)zz; }
/** Assigns a value to the untransformed coordinates for this point.
* @deprecated In favor of setXYZ(). */
public void setOrigXYZ(Tuple3 t)
{
this.setOrigX(t.getX());
this.setOrigY(t.getY());
this.setOrigZ(t.getZ());
}
//}}}
//{{{ get/setX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point */
public double getX()
{ return x0; }
/** Returns the untransformed coordinate for this point */
public double getY()
{ return y0; }
/** Returns the untransformed coordinate for this point */
public double getZ()
{ return z0; }
/** Assigns a value to the untransformed coordinate for this point */
public void setX(double xx) { x0 = (float)xx; }
/** Assigns a value to the untransformed coordinate for this point */
public void setY(double yy) { y0 = (float)yy; }
/** Assigns a value to the untransformed coordinate for this point */
public void setZ(double zz) { z0 = (float)zz; }
/** Assigns a value to the untransformed coordinates for this point */
public void setXYZ(double xx, double yy, double zz)
{
x0 = (float)xx;
y0 = (float)yy;
z0 = (float)zz;
}
//}}}
//{{{ get/setDrawX/Y/Z
//##################################################################################################
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawX()
{ return x; }
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawY()
{ return y; }
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawZ()
{ return z; }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawX(double xx) { x = (float)xx; }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawY(double yy) { y = (float)yy; }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawZ(double zz) { z = (float)zz; }
/** Assigns a value to the fully transformed (drawing) coordinates for this point */
public void setDrawXYZ(Tuple3 t)
{
x = (float)t.getX();
y = (float)t.getY();
z = (float)t.getZ();
}
//}}}
//{{{ get/setAllCoords, useCoordsXYZ
//##################################################################################################
/**
* Stores an array of coordinates for "high-dimensional" points.
* The float[] is stored without cloning and so is subject to overwrite.
*/
public void setAllCoords(float[] coords)
{ tmPut(COORDS_KEY, coords); }
/**
* Retrieves the "high-dimensional" coordinates of this point, or null if not set.
* The float[] is returned without cloning and so is subject to overwrite.
*/
public float[] getAllCoords()
{ return (float[]) tmGet(COORDS_KEY); }
/**
* Copies the high-dimensional coordinates at the specified indices
* into this point's (untransformed) X, Y, and Z fields.
* If a index is out of range (0-based), it is ignored and the value is not changed.
*/
public void useCoordsXYZ(int xIndex, int yIndex, int zIndex)
{
float[] coords = this.getAllCoords();
if(coords == null) return;
if((xIndex >= 0) && (xIndex < coords.length)) this.setX( coords[xIndex] );
if((yIndex >= 0) && (yIndex < coords.length)) this.setY( coords[yIndex] );
if((zIndex >= 0) && (zIndex < coords.length)) this.setZ( coords[zIndex] );
}
//}}}
//{{{ get/setOwner, get/setPrev, isBreak
//##################################################################################################
/** Determines the owner (parent) of this element */
public AGE getOwner()
{ return parent; }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{
parent = (KList)owner;
}
/**
* Sets the point that precedes this one.
* This matters to "chainable" points, like vectors and triangles.
* For other points, it does nothing.
* @param pt the point preceding this one in seqence
*/
public void setPrev(KPoint pt)
{
if(pt == null) multi &= ~SEQ_EVEN_BIT; // turn off
else if(pt instanceof AbstractPoint)
{
AbstractPoint apt = (AbstractPoint) pt;
if((apt.multi & SEQ_EVEN_BIT) != 0) multi &= ~SEQ_EVEN_BIT; // turn off
else multi |= SEQ_EVEN_BIT; // turn on
}
else multi &= ~SEQ_EVEN_BIT; // turn off
}
/**
* Gets the point preceding this one in the chain.
* @return the preceding point, or null if (a) this is a break in the chain or (b) this is not a chainable point type.
*/
public KPoint getPrev()
{ return null; }
/**
* True iff this is a chainable point type (e.g. vector, triangle) AND there is a chain break.
*/
public boolean isBreak()
{ return false; }
//}}}
//{{{ is/get/set{On, Unpickable, Ghost, Color, Aspects, Width, Radius, Comment}
//##################################################################################################
/** Indicates whether this element will paint itself, given the chance */
public boolean isOn()
{ return ((multi & ON_BIT) != 0); }
/** Sets the painting status of this element */
public void setOn(boolean paint)
{
if(paint) multi |= ON_BIT;
else multi &= ~ON_BIT;
}
/** Indicates whether this point can be picked with the mouse */
public boolean isUnpickable()
{ return ((multi & UNPICKABLE) != 0); }
/** Sets the picking status of this point */
public void setUnpickable(boolean b)
{
if(b) multi |= UNPICKABLE;
else multi &= ~UNPICKABLE;
}
/** Indicates whether this point is a "ghost" for Mage */
public boolean isGhost()
{ return ((multi & GHOST_BIT) != 0); }
/** Sets the ghost status of this point */
public void setGhost(boolean b)
{
if(b) multi |= GHOST_BIT;
else multi &= ~GHOST_BIT;
}
/** Returns the color of this point, or null if it inherits from its list */
public KPaint getColor()
{ return color; }
/** Sets the color of this point. */
public void setColor(KPaint c) { color = c; }
/** Gets the aspect string of this point */
public String getAspects() { return (String) tmGet(ASPECTS_KEY); }
/** Sets the aspect string of this point */
public void setAspects(String a) { tmPut(ASPECTS_KEY, a); }
/** Gets the line width of this point, if applicable */
public int getWidth()
{ return 0; }
/** Sets the line width of this point, if applicable */
public void setWidth(int w)
{}
/** Gets the radius of this point, if applicable */
public float getRadius()
{ return 0; }
/** Sets the radius of this point, if applicable */
public void setRadius(float radius)
{}
/** Sets the point comment for this point. */
public void setComment(String cmt)
{ tmPut(COMMENT_KEY, cmt); }
/** Gets the comment for this point, which defaults to null. */
public String getComment()
{ return (String) tmGet(COMMENT_KEY); }
//}}}
//{{{ getDrawingColor
//##################################################################################################
/** Returns the color that will be used to draw this point (ignoring aspects). Never null. */
public KPaint getDrawingColor()
{
KPaint paint = null;
//boolean byList = (engine.colorByList && parent != null);
// If live bit has been unset by a pointmaster, we're invisible!
if(!isOn()) paint = KPalette.invisible;
//else if(byList) paint = parent.color;
else if(color != null) paint = color;
else if(parent != null) paint = parent.color;
if(paint == null) paint = KPalette.defaultColor;
return paint;
}
/** Returns the color that will be used to draw this point, taking aspects into account. Never null. */
public KPaint getDrawingColor(Engine engine)
{
KPaint paint = null, tmppaint = null;
boolean byList = (engine.colorByList && parent != null);
String aspects = this.getAspects();
boolean doAspects = (engine.activeAspect > 0
&& aspects != null
&& aspects.length() >= engine.activeAspect);
// If live bit has been unset by a pointmaster, we're invisible!
if(!isOn()) paint = KPalette.invisible;
else if(byList) paint = parent.color;
// This way, we only use the aspect if we recognize the character
else if(doAspects && (tmppaint = KPalette.forAspect(aspects.charAt(engine.activeAspect-1))) != null)
paint = tmppaint;
else if(color != null) paint = color;
else if(parent != null) paint = parent.color;
if(paint == null) paint = KPalette.defaultColor;
return paint;
}
//}}}
//{{{ pmHit, pmWouldHit, get/setPmMask
//##################################################################################################
/**
* Processes a pointmaster on/off request.
* @param mask the bitmask indicating which masters are being turned on/off
* @param offmask the bitmask indicating which masters are already off
* @param turnon true
if affected points are to be turned on,
* false
if affected points are to be turned off.
*/
public void pmHit(int mask, int offmask, boolean turnon)
{
//Turn OFF if we're affected by this pointmaster, period.
//Turn ON if and only if all our other pointmasters are also ON already.
if(turnon)
{
if(( mask & pm_mask) != 0
&& (offmask & pm_mask) == 0) setOn(true);
}
else
{
if((mask & pm_mask) != 0) setOn(false);
}
}
/** Indicates whether or not the given pointmaster set would affect this point. */
public boolean pmWouldHit(int mask)
{ return (mask & pm_mask) != 0; }
public int getPmMask()
{ return pm_mask; }
public void setPmMask(int mask)
{ this.pm_mask = mask; }
//}}}
//{{{ calcBoundingBox() and calcRadiusSq()
//##################################################################################################
/**
* Gets a bounding box for the current model.
* @param bound the first 6 elements get set to { minX, minY, minZ, maxX, maxY, maxZ }.
* Should be called with { +inf, +inf, +inf, -inf, -inf, -inf }
*/
public void calcBoundingBox(float[] bound)
{
if(x0 < bound[0]) bound[0] = x0;
if(y0 < bound[1]) bound[1] = y0;
if(z0 < bound[2]) bound[2] = z0;
if(x0 > bound[3]) bound[3] = x0;
if(y0 > bound[4]) bound[4] = y0;
if(z0 > bound[5]) bound[5] = z0;
}
/**
* Gets the square of the radius of this model from the specified center.
* @param center an array with the x, y, and z coordinates of the center
* @return the square of the radius of this element, centered at center
*/
public float calcRadiusSq(float[] center)
{
float dx, dy, dz;
dx = x0 - center[0];
dy = y0 - center[1];
dz = z0 - center[2];
return (dx*dx + dy*dy + dz*dz);
}
//}}}
//{{{ signalTransform
//##################################################################################################
public void signalTransform(Engine engine, Transform xform)
{ signalTransform(engine, xform, 1.0); }
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
* This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
// We have to transform whether we're on or not, because dependent points
// (vectors, triangles) may be on and expect our coords to be valid.
// Point-on is checked during drawing and picking by getDrawingColor.
xform.transform(this, engine.work1);
setDrawXYZ(engine.work1);
engine.addPaintable(this, z);
}
//}}}
//{{{ isPickedBy
//##################################################################################################
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{ return _isPickedBy(xx, yy, radius, objPick); }
// For BallPoint and RingPoint, because Java doesn't allow super.super:
KPoint _isPickedBy(float xx, float yy, float radius, boolean objPick)
{
float deltax, deltay;
deltax = (x - xx);
deltay = (y - yy);
if((deltax*deltax + deltay*deltay) <= radius*radius) return this;
else return null;
}
//}}}
//{{{ equals(), hashCode()
//##################################################################################################
// These functions are for identifying points that occupy the same location in space.
/** Tests two KPoints to see if they occupy the same space */
public boolean equals(Object obj)
{
if(obj == null || !(obj instanceof KPoint)) return false;
KPoint p = (KPoint)obj;
if(getX() == p.getX() && getY() == p.getY() && getZ() == p.getZ()) return true;
else return false;
}
/** Generates a hashcode based on the coordinates of this point */
public int hashCode()
{
/* I stole this from Colt: */
// this avoids excessive hashCollisions
// in the case values are of the form (1.0, 2.0, 3.0, ...)
int b1 = Float.floatToIntBits(x0*663608941.737f);
int b2 = Float.floatToIntBits(y0*663608941.737f);
int b3 = Float.floatToIntBits(z0*663608941.737f);
// The rotation of bits is my own idea
return (b1 ^ (b2<<11 | b2>>>21) ^ (b3<<22 | b3>>>10));
/* I stole this from Colt: */
/* Old version * /
int b1 = Float.floatToIntBits(x0);
int b2 = Float.floatToIntBits(y0);
int b3 = Float.floatToIntBits(z0);
// The rotation of bits is my own idea
return (b1 ^ b2 ^ b3);
/* Old version */
}
//}}}
//{{{ tmGet, tmPut, tmRemove
//##############################################################################
/**
* Returns the value associated with the given key,
* or null if this map does not contain that key.
*/
Object tmGet(int key)
{
int keyMap = this.multi & TINYMAP_AND;
if(!TinyMap.contains(key, keyMap)) return null;
else return tmValues[TinyMap.indexOf(key, keyMap)];
}
/**
* Associates a new value with key and returns the old value,
* or null if none was set.
*/
Object tmPut(int key, Object value)
{
int keyMap = this.multi & TINYMAP_AND;
int i = TinyMap.indexOf(key, keyMap);
if(TinyMap.contains(key, keyMap))
{
Object old = tmValues[i];
tmValues[i] = value;
return old;
}
else
{
int tmValues_length = TinyMap.size(keyMap); //tmValues may be null!
this.multi |= (1 << key) & TINYMAP_AND;
Object[] newvals = new Object[tmValues_length+1];
for(int j = 0; j < i; j++) newvals[j] = tmValues[j];
newvals[i] = value;
for(int j = i; j < tmValues_length; j++) newvals[j+1] = tmValues[j];
tmValues = newvals;
return null;
}
}
/** Removes the value for the given key, if present. */
Object tmRemove(int key)
{
int keyMap = this.multi & TINYMAP_AND;
if(!TinyMap.contains(key, keyMap)) return null;
int i = TinyMap.indexOf(key, keyMap);
Object old = tmValues[i];
this.multi &= ~((1 << key) & TINYMAP_AND);
Object[] newvals = new Object[tmValues.length-1];
for(int j = 0; j < i; j++) newvals[j] = tmValues[j];
for(int j = i+1; j < tmValues.length; j++) newvals[j-1] = tmValues[j];
tmValues = newvals;
if(tmValues.length == 0) tmValues = null; // just to save space
return old;
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KPalette.java 0000644 0000000 0000000 00000031127 11531212670 020256 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.data.*;
//}}}
/**
* KPalette
organizes the canonical Mage colors.
* This class is an incompatible, 3rd-generation replacement
* for ColorManager.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Wed Jun 25 15:37:14 EDT 2003
*/
public class KPalette //extends ... implements ...
{
//{{{ Pens
/** Scaling factors for width at different depth-cue levels */
public static final float[] widthScale = new float[KPaint.COLOR_LEVELS];
/** A zero-width pen for objects that should be filled instead. */
public static final BasicStroke pen0 = new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
/** A one pixel thick pen for ordinary drawing. */
public static final BasicStroke pen1 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
/** The set of various pens for drawing depth-cued lines in different widths. */
public static final BasicStroke[][] pens = new BasicStroke[7][KPaint.COLOR_LEVELS];
/** The set of line widths used for basic drawing, adjusted by widthScale. */
public static final int[][] lineWidths = new int[7][KPaint.COLOR_LEVELS];
/**
* This version of line widths emulates MAGE.
* Line width multipliers scale linearly from 0.5 to 2.0.
* It's not realistic with respect to the laws of optical perspective,
* but it is more pronounced than my old version.
*/
static
{
for(int i = 0; i < KPaint.COLOR_LEVELS; i++)
{
double a = i / (KPaint.COLOR_LEVELS-1.0);
widthScale[i] = (float)(a*2.0 + (1-a)*0.5);
}
// No depth cueing by width for really thin lines
for(int j = 0; j < KPaint.COLOR_LEVELS; j++)
{
lineWidths[0][j] = 1;
pens[0][j] = pen1;
}
// All other line thicknesses get depth cueing
for(int i = 1; i < 7; i++)
{
for(int j = 0; j < KPaint.COLOR_LEVELS; j++)
{
lineWidths[i][j] = Math.max(1, (int)((i+1)*widthScale[j] + 0.5));
pens[i][j] = new BasicStroke((i+1)*widthScale[j], BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
}
}
}
/** Jane feels this doesn't give a strong enough effect * /
// I don't remember what this code is calculating anymore.
// I think it has to do with perspective, so that lines
// shrink in the background as though they were cylinders
// according to the normal rules of perspective.
static
{
double half = (KPaint.COLOR_LEVELS-1.0) / 2.0;
double quot = 3.0 * half;
for(int i = 0; i < KPaint.COLOR_LEVELS; i++)
{
widthScale[i] = (float)(1.0 / (1.0 - (i-half)/quot));
}
for(int i = 0; i < 7; i++)
{
for(int j = 0; j < KPaint.COLOR_LEVELS; j++)
{
pens[i][j] = new BasicStroke((i+1)*widthScale[j], BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
}
}
}
/** Jane feels this doesn't give a strong enough effect */
//}}}
//{{{ Colors
//##################################################################################################
// Create standard entries
// name hue bSat wSat bVal wVal
//public static final KPaint defaultColor = KPaint.createHSV("default", 0, 0, 0, 100, 0);
public static final KPaint red = KPaint.createHSV("red", 0, 100, 100, 100, 80);
public static final KPaint orange = KPaint.createHSV("orange", 20, 100, 100, 100, 90);
//public static final KPaint rust = KPaint.createHSV("rust", 20, 100, 100, 100, 90);
public static final KPaint gold = KPaint.createHSV("gold", 40, 100, 100, 100, 90);
public static final KPaint yellow = KPaint.createHSV("yellow", 60, 100, 100, 100, 90);
public static final KPaint lime = KPaint.createHSV("lime", 80, 100, 100, 100, 85);
public static final KPaint green = KPaint.createHSV("green", 120, 80, 90, 100, 75);
public static final KPaint sea = KPaint.createHSV("sea", 150, 100, 100, 100, 85);
//public static final KPaint seagreen = KPaint.createHSV("seagreen", 150, 100, 100, 100, 85);
public static final KPaint cyan = KPaint.createHSV("cyan", 180, 100, 85, 85, 80);
public static final KPaint sky = KPaint.createHSV("sky", 210, 75, 80, 95, 90);
//public static final KPaint skyblue = KPaint.createHSV("skyblue", 210, 75, 80, 95, 90);
public static final KPaint blue = KPaint.createHSV("blue", 240, 70, 80, 100, 100);
public static final KPaint purple = KPaint.createHSV("purple", 275, 75, 100, 100, 85);
public static final KPaint magenta = KPaint.createHSV("magenta", 300, 95, 100, 100, 90);
public static final KPaint hotpink = KPaint.createHSV("hotpink", 335, 100, 100, 100, 90);
public static final KPaint pink = KPaint.createHSV("pink", 350, 55, 75, 100, 90);
public static final KPaint peach = KPaint.createHSV("peach", 25, 75, 75, 100, 90);
public static final KPaint lilac = KPaint.createHSV("lilac", 275, 55, 75, 100, 80);
public static final KPaint pinktint = KPaint.createHSV("pinktint", 340, 30, 100, 100, 55);
public static final KPaint peachtint = KPaint.createHSV("peachtint", 25, 50, 100, 100, 60);
public static final KPaint yellowtint = KPaint.createHSV("yellowtint",60, 50, 100, 100, 75);
//public static final KPaint paleyellow = KPaint.createHSV("paleyellow",60, 50, 100, 100, 75);
public static final KPaint greentint = KPaint.createHSV("greentint", 135, 40, 100, 100, 35);
public static final KPaint bluetint = KPaint.createHSV("bluetint", 220, 40, 100, 100, 50);
public static final KPaint lilactint = KPaint.createHSV("lilactint", 275, 35, 100, 100, 45);
public static final KPaint white = KPaint.createHSV("white", 0, 0, 0, 100, 0);
public static final KPaint gray = KPaint.createHSV("gray", 0, 0, 0, 50, 40);
//public static final KPaint grey = KPaint.createHSV("grey", 0, 0, 0, 50, 40);
public static final KPaint brown = KPaint.createHSV("brown", 20, 45, 45, 75, 55);
public static final KPaint deadwhite = KPaint.createSolid("deadwhite", KPaint.white);
public static final KPaint deadblack = KPaint.createSolid("deadblack", KPaint.black);
//public static final KPaint black = KPaint.createSolid("black", Color.black);
public static final KPaint invisible = KPaint.createInvisible("invisible");
public static final KPaint defaultColor = white;
//}}}
//{{{ Color map
//##################################################################################################
private static final Map stdColorMap; // unmodifiable once created
private static final Map fullColorMap; // unmodifiable once created
static
{
Map map = new UberMap();
map.put(red.toString(), red);
map.put(pink.toString(), pink);
map.put(pinktint.toString(), pinktint);
map.put(orange.toString(), orange);
map.put(peach.toString(), peach);
map.put(peachtint.toString(), peachtint);
map.put(gold.toString(), gold);
map.put(yellow.toString(), yellow);
map.put(yellowtint.toString(), yellowtint);
map.put(lime.toString(), lime);
map.put(green.toString(), green);
map.put(greentint.toString(), greentint);
map.put(sea.toString(), sea);
map.put(cyan.toString(), cyan);
map.put(sky.toString(), sky);
map.put(blue.toString(), blue);
map.put(bluetint.toString(), bluetint);
map.put(purple.toString(), purple);
map.put(lilac.toString(), lilac);
map.put(lilactint.toString(), lilactint);
map.put(magenta.toString(), magenta);
map.put(hotpink.toString(), hotpink);
map.put(white.toString(), white);
map.put(gray.toString(), gray);
map.put(brown.toString(), brown);
map.put(deadwhite.toString(), deadwhite);
map.put(deadblack.toString(), deadblack);
map.put(invisible.toString(), invisible);
stdColorMap = Collections.unmodifiableMap(map);
map = new UberMap(map);
map.put("default", defaultColor);
map.put("rust", orange);
map.put("seagreen", sea);
map.put("skyblue", sky);
map.put("paleyellow", yellowtint);
map.put("grey", gray);
map.put("black", deadblack);
fullColorMap = Collections.unmodifiableMap(map);
}
//}}}
//{{{ Aspect table
//##################################################################################################
private static final KPaint[] aspectTable;
static
{
aspectTable = new KPaint[256];
Arrays.fill(aspectTable, null);
addAspect('A', red);
addAspect('B', orange);
addAspect('C', gold);
addAspect('D', yellow);
addAspect('E', lime);
addAspect('F', green);
addAspect('G', sea);
addAspect('H', cyan);
addAspect('I', sky);
addAspect('J', blue);
addAspect('K', purple);
addAspect('L', magenta);
addAspect('M', hotpink);
addAspect('N', pink);
addAspect('O', lilac);
addAspect('P', peach);
addAspect('Q', peachtint);
addAspect('R', yellowtint);
addAspect('S', greentint);
addAspect('T', bluetint);
addAspect('U', lilactint);
addAspect('V', pinktint);
addAspect('W', white);
addAspect('X', gray);
addAspect('Y', brown);
addAspect('Z', invisible);
}
static private void addAspect(char key, KPaint color)
{
int upper = Character.toUpperCase(key);
int lower = Character.toLowerCase(key);
aspectTable[upper] = aspectTable[lower] = color;
}
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Not instantiable
*/
private KPalette()
{
}
//}}}
//{{{ forName, forAspect, getStandard/FullMap
//##################################################################################################
/** Returns the named KPaint or null if none is known. */
static public KPaint forName(String name)
{ return (KPaint)fullColorMap.get(name); }
/** Returns the KPaint for the given aspect, or null if bad aspect */
static public KPaint forAspect(char aspect)
{
if(aspect < 0 || aspect > 255) return null;
else return aspectTable[aspect];
}
/**
* Returns a Map<String, KPaint> of the predefined Mage colors.
* This map includes one entry for each unique color, using its preferred name.
*/
static public Map getStandardMap()
{ return stdColorMap; }
/**
* Returns a Map<String, KPaint> of the predefined Mage colors.
* This map includes extra entries for alternate spellings and
* older, deprecated color names.
*/
static public Map getFullMap()
{ return fullColorMap; }
//}}}
//{{{ setContrast
//##################################################################################################
/**
* Adjusts the contrast for the entire palette.
* A contrast of less than 1.0 is flat, and greater than 1.0 is exagerated.
*/
static public void setContrast(double alpha)
{
for(Iterator iter = getFullMap().values().iterator(); iter.hasNext(); )
{
KPaint p = (KPaint) iter.next();
p.setContrast(alpha);
}
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/TransformSignal.java 0000644 0000000 0000000 00000011240 11531212670 021650 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* TransformSignal
provides a reusable framework
* for publish-subscribe message passing.
* This signal is used to transform a 3-D object and paint it
* on a flat 2-D display (the screen, a printer, etc).
*
* This signal is not thread-safe.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Thu Mar 27 10:11:30 EST 2003
*/
public class TransformSignal implements TransformSignalSubscriber
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
ArrayList subscribers;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public TransformSignal()
{
subscribers = new ArrayList();
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method will publish this signal (i.e., call this method)
* for each subscriber, one at a time, in the current thread.
* Because this class also implements the subscriber interface,
* these signals can be chained together to create deep networks.
*
*
A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
TransformSignalSubscriber subscriber;
Iterator iter = subscribers.iterator();
while(iter.hasNext())
{
subscriber = (TransformSignalSubscriber)iter.next();
subscriber.signalTransform(engine, xform);
}
}
//}}}
//{{{ subscribe, getSubscribers
//##################################################################################################
/**
* Adds a subscriber to this signal. The subscriber will be notified
* whenever this signal is activated. Every subscriber must be unique,
* so if there is some current subscriber oldSubscriber such that
* newSubscriber.equals(oldSubscriber)
, then oldSubscriber
* will be removed before newSubscriber is added.
*
*
Subscribers are notified in the same order they were added; however,
* they should NOT rely on this as it may change in future implementations.
*/
public void subscribe(TransformSignalSubscriber newSubscriber)
{
if(newSubscriber == null) return;
int i = subscribers.indexOf(newSubscriber);
if(i != -1) subscribers.remove(i);
subscribers.add(newSubscriber);
}
/** Returns an unmodifiable Collection of the current subscriber list */
public Collection getSubscribers()
{ return Collections.unmodifiableCollection(subscribers); }
//}}}
//{{{ unsubscribe, unsubscribeAll
//##################################################################################################
/**
* Removes a subscriber from this signal; the subscriber will no
* longer be notified when this signal is activated.
* @return the subscriber that was removed, or null if oldSubscriber was not subscribed
*/
public TransformSignalSubscriber unsubscribe(TransformSignalSubscriber oldSubscriber)
{
if(oldSubscriber == null) return null;
int i = subscribers.indexOf(oldSubscriber);
if(i != -1) return (TransformSignalSubscriber)subscribers.remove(i);
else return null;
}
/**
* Removes all subscribers from this signal's distribution list.
*/
public void unsubscribeAll()
{ subscribers.clear(); }
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/RecursivePointIterator.java 0000644 0000000 0000000 00000010063 11531212670 023234 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* RecursivePointIterator
is an iterator over
* all the points beneath a given AGE. It is used by
* searching functions, etc.
*
*
This function may fail with a java.util.ConcurrentModificationException
* if the structure of the kinemage is modified during the search
* (i.e., add/remove groups, subgroups, or lists).
*
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*
Begun on Thu Dec 19 10:57:57 EST 2002
*/
public class RecursivePointIterator //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
LinkedList iterStack;
Iterator iter;
KPoint next;
boolean findTurnedOff; // ignore points/AGEs that are not ON
boolean findUnpickable; // ignore points that are unpickable
//}}}
//{{{ Constructor(s)
//##################################################################################################
public RecursivePointIterator(AGE top, boolean findTurnedOff, boolean findUnpickable)
{
iterStack = new LinkedList();
iter = top.iterator();
next = null;
this.findTurnedOff = findTurnedOff;
this.findUnpickable = findUnpickable;
}
public RecursivePointIterator(AGE top)
{ this(top, false, false); }
//}}}
//{{{ nextImpl
//##################################################################################################
/**
* Function that searches the tree for the next KPoint
* and places it into the variable next.
* If there are no more points, next == null.
*/
private void nextImpl()
{
// True tail-recursion has been replaced by a while-loop pseudo-recursion
// because otherwise we tend to get StackOverflowErrors.
// If Java was smarter it would perform this optimization for us... ;)
while(true)
{
if(iter.hasNext())
{
Object o = iter.next();
if(o instanceof KPoint
&& (findTurnedOff || ((KPoint)o).isOn())
&& (findUnpickable || !((KPoint)o).isUnpickable()) )
{
next = (KPoint)o;
return; // recursion bottoms out here (success)
}
else if(o instanceof AGE
&& (findTurnedOff || ((AGE)o).isOn()) )
{
iterStack.addLast(iter);
iter = ((AGE)o).iterator();
// recurses
}
// else recurses: we can ignore it and move on
}
else if(!iterStack.isEmpty())
{
iter = (Iterator)iterStack.removeLast();
// recurses
}
else
{
next = null;
return; // recursion bottoms out here (failure)
}
}
}
//}}}
//{{{ next, hasNext
//##################################################################################################
/**
* Returns the next KPoint, if there is one, or null if there isn't.
*/
public KPoint next()
{
// hasNext() may have already stocked next for us
if(next == null) nextImpl();
KPoint retval = next;
// mark this value as consumed
next = null;
return retval;
}
/**
* Returns true if there is another point available (and it's not null,
* but lists should never contain null points).
*/
public boolean hasNext()
{
if(next == null) nextImpl();
return (next != null);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/Engine.java 0000644 0000000 0000000 00000070143 11531212670 017753 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
import driftwood.r3.*;
import driftwood.util.*;;
//}}}
/**
* Engine
is responsible for transforming coordinates, Z-buffering,
* and requesting that points render themselves.
*
*
Begun on Mon Apr 22 17:21:31 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*/
public class Engine //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variables
//##################################################################################################
/** READ ONLY: The highest layer in the rendering Z-buffer */
public final int TOP_LAYER;
// READ ONLY: Parameters for transforming geometry
public Transform xform3D = null;
public Transform xform2D = null;
public double zoom3D = 1;
public double zoom2D = 1;
public double clipBack = 0;
public double clipFront = 1;
public double clipDepth = 1;
public double perspDist = 2000;
// READ ONLY: Parameters for painting points
public Painter painter = null;
public boolean useObjPicking = false; // should we pick triangles, lines, balls as solid objects?
public boolean useStereo = false;
public float stereoRotation = 0;
public boolean bigMarkers = false;
public boolean bigLabels = false;
public boolean cueIntensity = true;
public boolean monochrome = false;
public int widthCue = 0; // cue passed to point, between 0 and 4
public int colorCue = 0; // cue passed to point, between 0 and 4
public int activeAspect = 0; // 0 -> don't use aspects, x -> use aspect x if present
public int markerSize = 1;
public Font labelFont = null;
public int backgroundMode = -1;
public Triple lightingVector = new Triple(-1, 1, 3).unit();
public Rectangle pickingRect = new Rectangle(); // bounds of one side of stero area or whole canvas
// READ ONLY: These are set from Kinemage obj by KinCanvas on every drawing pass.
// Changing them here will have NO EFFECT because they'll be overwritten.
public boolean usePerspective = false;
public boolean cueThickness = false;
public boolean thinLines = false;
public boolean whiteBackground = false;
public boolean colorByList = false;
// READ/WRITE: Shared "scratch" objects that points can use
public Triple work1 = new Triple();
public Triple work2 = new Triple();
public Dimension dim1 = new Dimension();
// FOR USE BY ENGINE ONLY
ArrayList[] zbuffer;
HashMap ballmap; // Map for line shortening
ArrayList[] parents; // KList that is acting parent for each pt in zbuffer; default is null
KList actingParent = null; // KList that is parent for each pt as added; null = no change
// See setActingParent() for a description of the stupid hijinks we're pulling here.
// Things needed to support multiple clipping planes:
double viewClipBack = -1, viewClipFront = 1, viewClipScaling = 1;
Map frontClipMap = new HashMap(), backClipMap = new HashMap();
Font bigFont, smallFont;
Rectangle canvasRect = new Rectangle();
float pickingRadius = 5f;
boolean warnedPickingRegion = false; // have we warned user about out-of-bounds picks?
boolean transparentBackground = false; // used only for certain export features
//}}}
//{{{ Constructor
//##################################################################################################
/**
* Creates a new rendering engine.
*/
public Engine()
{
TOP_LAYER = 1000;
flushZBuffer();
stereoRotation = (float)Math.toRadians(6.0);
bigFont = new Font("SansSerif", Font.PLAIN, 24);
smallFont = new Font("SansSerif", Font.PLAIN, 12);
}
//}}}
//{{{ render
//##################################################################################################
/**
* Transforms the given TransformSignalSubscriber and renders it to a graphics context.
* @param subscriber the subscriber that will be transformed and rendered
* @param view a KingView representing the current rotation/zoom/clip
* @param bounds the bounds of the area to render to
* @param painter the Painter that should be used for rendering stuff this pass
*/
public void render(TransformSignalSubscriber subscriber, KingView view, Rectangle bounds, Painter painter)
{
// The game plan:
// 1. Paint background
// 2. Load drawing variables
// 3. For each region (there are 2 for stereo):
// a. Transform the coordinates from model-space to screen-space,
// add transformed objects to Z-buffer.
// b. Paint all objects in Z-buffer, from back to front.
this.painter = painter;
this.canvasRect.setBounds(bounds);
// Get colors and prepare the graphics device
painter.setViewport(bounds.x, bounds.y, bounds.width, bounds.height);
Color backgroundClearColor;
if(whiteBackground)
{
if(monochrome) backgroundMode = KPaint.WHITE_MONO;
else backgroundMode = KPaint.WHITE_COLOR;
backgroundClearColor = KPaint.white;
}
else
{
if(monochrome) backgroundMode = KPaint.BLACK_MONO;
else backgroundMode = KPaint.BLACK_COLOR;
backgroundClearColor = KPaint.black;
}
if(this.transparentBackground)
{
backgroundClearColor = new Color(
backgroundClearColor.getRed(),
backgroundClearColor.getGreen(),
backgroundClearColor.getBlue(),
0); // alpha = 0 --> transparent
this.transparentBackground = false; // disabled after one pass
}
painter.clearCanvas(backgroundClearColor);
// Set some last-minute drawing variables
markerSize = (bigMarkers ? 2 : 1);
labelFont = (bigLabels ? bigFont : smallFont);
painter.setFont(labelFont);
if(useStereo)
{
int halfwidth = Math.max(0, bounds.width/2 - 10);
// This way, toggling cross-eye vs wall-eye just swaps the two images!
// This makes figure-making much easier, as you can easily do both versions.
KingView leftView = (KingView)view.clone(), rightView = (KingView)view.clone();
if(stereoRotation < 0) leftView.rotateY(stereoRotation);
else rightView.rotateY(-stereoRotation);
Rectangle clipRgn = new Rectangle();
clipRgn.setBounds( bounds.x, bounds.y, halfwidth, bounds.height);
painter.setViewport(bounds.x, bounds.y, halfwidth, bounds.height);
renderLoop(subscriber, leftView, clipRgn);
clipRgn.setBounds( (bounds.x + bounds.width - halfwidth), bounds.y, halfwidth, bounds.height);
painter.setViewport((bounds.x + bounds.width - halfwidth), bounds.y, halfwidth, bounds.height);
renderLoop(subscriber, rightView, clipRgn);
// Have to re-activate all of the screen for drawing during overpaint
painter.setViewport(bounds.x, bounds.y, bounds.width, bounds.height);
}
else//!useStereo
{
renderLoop(subscriber, view, bounds);
}
}
//}}}
//{{{ renderLoop
//##################################################################################################
/**
* Transforms the given TransformSignalSubscriber and renders it to a graphics context.
* @param subscriber the subscriber that will be transformed and rendered
* @param view a KingView representing the current rotation/zoom/clip
* @param bounds the bounds of the area to render to.
* Note that this function does not clip g to ensure that it only paints within these bounds!
*/
void renderLoop(TransformSignalSubscriber subscriber, KingView view, Rectangle bounds)
{
int i, j, end_j; // loop over z-buffer, thru z-buffer
ArrayList zb; // == zbuffer[i], saves array lookups
ArrayList pnt; // == parents[i], saves array lookups
// Clear the cache of old paintables
for(i = 0; i <= TOP_LAYER; i++)
{
zbuffer[i].clear();
parents[i].clear();
}
ballmap.clear();
// Transform the paintables
xform3D = create3DTransform(view, bounds);
xform2D = create2DTransform(bounds);
this.chooseClipMode(null); // default to std clipping planes
subscriber.signalTransform(this, xform3D);
pickingRect.setBounds(bounds); // save these bounds as the picking region
// Now paint them to the graphics
for(i = 0; i <= TOP_LAYER; i++)
{
// Calculate depth-cueing constants for this level
if(cueIntensity) colorCue = (KPaint.COLOR_LEVELS*i)/(TOP_LAYER+1);
else colorCue = KPaint.COLOR_LEVELS - 1;
if(cueThickness) widthCue = (KPaint.COLOR_LEVELS*i)/(TOP_LAYER+1);
else widthCue = (KPaint.COLOR_LEVELS-1) / 2;
//if(colorCue >= KPaint.COLOR_LEVELS)
// SoftLog.err.println("colorCue = "+colorCue+"; i = "+i+"; TOP_LAYER = "+TOP_LAYER);
// Render all points at this level (faster to not use iterators)
zb = zbuffer[i];
pnt = parents[i];
end_j = zb.size();
for(j = 0; j < end_j; j++)
{
KPoint pt = (KPoint) zb.get(j);
KList l = (KList) pnt.get(j);
if(l == null)
pt.paintStandard(this);
else // see setActingParent() for an explanation
{
AGE oldPnt = pt.getOwner();
pt.setOwner(l);
pt.paintStandard(this);
pt.setOwner(oldPnt);
}
}
}
}
//}}}
//{{{ create3DTransform
//##################################################################################################
/**
* Builds a Transform suitable for use with TransformSignal.
* @param view a KingView describing the current rotation, zoom, and clipping
* @param bounds the region of the Component where the Paintables will be rendered
*/
public Transform create3DTransform(KingView view, Rectangle bounds)
{
double width, height, size, xOff, yOff;
width = bounds.getWidth();
height = bounds.getHeight();
size = Math.min(width, height);
xOff = bounds.getX() + width/2.0;
yOff = bounds.getY() + height/2.0;
this.viewClipScaling = size/2.0;
// Get information from the current view
double cx, cy, cz, R11, R12, R13, R21, R22, R23, R31, R32, R33;
synchronized(view)
{
view.compile();
zoom3D = size / view.getSpan();
cx = view.cx;
cy = view.cy;
cz = view.cz;
R11 = view.R11;
R12 = view.R12;
R13 = view.R13;
R21 = view.R21;
R22 = view.R22;
R23 = view.R23;
R31 = view.R31;
R32 = view.R32;
R33 = view.R33;
viewClipFront = view.getClip();
viewClipBack = -viewClipFront;
}
// Build our transform
Transform ret = new Transform(), work = new Transform();
work.likeTranslation(-cx, -cy, -cz); // center on rotation center
ret.append(work);
work.likeMatrix(R11, R12, R13, R21, R22, R23, R31, R32, R33); // rotate
ret.append(work);
work.likeScale(zoom3D); // zoom
ret.append(work);
if(usePerspective)
{
perspDist = 5.0 * size;
work.likePerspective(perspDist);
ret.append(work);
}
work.likeScale(1, -1, 1); // invert Y axis
ret.append(work);
work.likeTranslation(xOff, yOff, 0); // center on screen
ret.append(work);
return ret;
}
//}}}
//{{{ create2DTransform
//##################################################################################################
/**
* Builds a Transform suitable for use with TransformSignal.
* @param bounds the region of the Component where the Paintables will be rendered
*/
public Transform create2DTransform(Rectangle bounds)
{
double width, height, size, xOff, yOff;
width = bounds.getWidth();
height = bounds.getHeight();
size = Math.min(width, height);
xOff = bounds.getX() + width/2.0;
yOff = bounds.getY() + height/2.0;
zoom2D = size / 400.0;
// Build our transform
Transform ret = new Transform(), work = new Transform();
work.likeScale(zoom2D); // resize to fill screen
ret.append(work);
work.likeScale(1, -1, 1); // invert Y axis
ret.append(work);
work.likeTranslation(xOff, yOff, 0); // center on screen
ret.append(work);
return ret;
}
//}}}
//{{{ setActingParent
//##################################################################################################
/**
* This is a *really* dumb hack that allows us to implement Mage's instance=
* feature fairly cheaply in terms of both time and space.
* The idea is that each point in the zbuffer will be associated with a KList
* object that *should* own it for drawing purposes.
* For most KPoints, this should be the one KList they belong to,
* but we choose to record null
instead to save a few operations.
* If something else is stored, we set the point's owner to the specified list
* just for the duration of the drawing operation, to ensure it appears in the
* correct color, width, radius, etc.
* Most normal lists should call this function with the parameter null
* before beginning to transform their points.
* Lists that are "instances" of other lists will instead pass in this
* (but should remember to reset to null after transforming all their points).
*/
public void setActingParent(KList pnt)
{
this.actingParent = pnt;
}
//}}}
//{{{ chooseClipMode, putClipMode
//##################################################################################################
/**
* Enables an arbitrary number of clipping planes (all normal to the line of sight)
* to be used for clipping various parts of the kinemage.
* @param key a unique identifier for this set of planes (e.g. new Object())
* @param front the front clipping plane, in view units (positive)
* @param back the back clipping plane, in view units (negative)
*/
public void putClipMode(Object key, double front, double back)
{
if(key == null) return;
frontClipMap.put(key, new Double(front));
backClipMap.put(key, new Double(back));
}
/**
* Selects a clipping mode based on the key used for putClipMode().
* A null key selects the default (KingView) clipping planes.
*/
public void chooseClipMode(Object key)
{
this.clipFront = this.viewClipFront;
this.clipBack = this.viewClipBack;
if(key != null)
{
Double d = (Double) frontClipMap.get(key);
if(d != null) this.clipFront = d.doubleValue();
d = (Double) backClipMap.get(key);
if(d != null) this.clipBack = d.doubleValue();
}
// Convert from KingView units to pixel units
this.clipFront *= viewClipScaling;
this.clipBack *= viewClipScaling;
if(usePerspective)
{
// We also have to move clipping planes
// because this alters z coords too.
// See driftwood.r3.Transform.likePerspective()
// for more detailed explanation.
clipFront = perspDist*clipFront / (perspDist - clipFront);
clipBack = perspDist*clipBack / (perspDist - clipBack);
}
this.clipDepth = clipFront - clipBack;
}
//}}}
//{{{ addPaintable, addPaintableToLayer, flushZBuffer
//##################################################################################################
/**
* Registers a paintable to be drawn to the screen.
* @param p the KPoint to be rendered.
* @param zcoord the Z coordinate of the transformed object.
* A layer number is calculated automatically from this.
*/
public void addPaintable(KPoint p, double zcoord)
{
addPaintableToLayer(p, (int)(TOP_LAYER*(zcoord-clipBack)/clipDepth));
}
/**
* Registers a paintable to be drawn to the screen.
* @param p the KPoint to be rendered.
* @param layer a number between 0 and TOP_LAYER, inclusive, that
* determines the order of rendering. Objects at 0 are furthest from
* the observer and are rendered first; objects in the TOP_LAYER are
* closest to the observer and are rendered last.
*/
public void addPaintableToLayer(KPoint p, int layer)
{
if(layer < 0 || layer > TOP_LAYER || p == null) return;
zbuffer[layer].add(p);
parents[layer].add(actingParent);
}
/**
* This may need to be called to reclaim memory when kinemages are closed.
*/
public void flushZBuffer()
{
zbuffer = null;
zbuffer = new ArrayList[TOP_LAYER+1];
for(int i = 0; i <= TOP_LAYER; i++)
{
zbuffer[i] = new ArrayList(10);
}
parents = null;
parents = new ArrayList[TOP_LAYER+1];
for(int i = 0; i <= TOP_LAYER; i++)
{
parents[i] = new ArrayList(10);
}
ballmap = null;
ballmap = new HashMap(1000);
//ballmap = new OdHash(1000);
}
//}}}
//{{{ addShortener, getShortening
//##################################################################################################
/**
* Registers the given point as having some radius that other
* objects should respect. In particular, this radius will be
* used to shorten lines that originate/terminate at this location.
*/
public void addShortener(KPoint p, double radius)
{
Double old = (Double)ballmap.get(p);
if(old == null || old.doubleValue() < radius) ballmap.put(p, new Double(radius));
//double old = ballmap.get(p, 0);
//if(old < radius) ballmap.put(p, radius);
}
/**
* Returns the amount of shortening, between 0 and +inf,
* that should be applied at the given point.
*/
public double getShortening(KPoint p)
{
Double radius = (Double)ballmap.get(p);
if(radius == null) return 0;
else return radius.doubleValue();
//return ballmap.get(p, 0);
}
//}}}
//{{{ updatePrefs, syncToKin
//##################################################################################################
// Called by KingMain when something happens.
// Shouldn't be called directly under normal circumstances.
public void updatePrefs(Props prefs)
{
stereoRotation = (float)Math.toRadians(prefs.getDouble("stereoAngle"));
bigFont = new Font("SansSerif", Font.PLAIN, prefs.getInt("fontSizeBig"));
smallFont = new Font("SansSerif", Font.PLAIN, prefs.getInt("fontSizeSmall"));
this.setPickingRadius( prefs.getDouble("pickingRadius") );
useObjPicking = prefs.getBoolean("pickObjects");
}
/** Takes needed display settings from the kinemage */
public void syncToKin(Kinemage kin)
{
if(kin.currAspect == null) this.activeAspect = 0;
else this.activeAspect = kin.currAspect.getIndex().intValue();
this.usePerspective = kin.atPerspective;
this.cueThickness = ! kin.atOnewidth;
this.thinLines = kin.atThinline;
this.whiteBackground = kin.atWhitebackground;
this.colorByList = kin.atListcolordominant;
}
//}}}
//{{{ pickPoint, setPickingRadius
//##################################################################################################
/**
* Finds the point clicked on with the mouse.
* @param xcoord the x coord of the pick, relative to the drawing surface
* @param ycoord the y coord of the pick, relative to the drawing surface
* @param superpick if true, even pick points marked as unpickable
* @return the KPoint that was selected
*/
public KPoint pickPoint(int xcoord, int ycoord, boolean superpick)
{
if(!pickingRect.contains(xcoord, ycoord))
{
if(!warnedPickingRegion)
{
JCheckBox dontWarn = new JCheckBox("Don't warn me again", false);
JOptionPane.showMessageDialog(null,
new Object[] {
"When using stereo, only the right-hand half\n"+
"of the screen is active for picking.",
dontWarn
},
"Out-of-bounds pick",
JOptionPane.WARNING_MESSAGE);
warnedPickingRegion = dontWarn.isSelected();
}
return null;
}
// Iterate over all levels and all points in each level, searching for "the one"
int i, j, end_j; // loop over z-buffer
ArrayList zb; // == zbuffer[i], saves array lookups
KPoint theone = null, p, q;
// Note: looping front to back, rather than back to front as in render()
for(i = TOP_LAYER; i >= 0 && theone == null; i--)
{
zb = zbuffer[i];
end_j = zb.size();
for(j = 0; j < end_j && theone == null; j++)
{
p = (KPoint)zb.get(j);
// q will usually be p or null, but sometimes not for object picking
q = p.isPickedBy(xcoord, ycoord, pickingRadius, useObjPicking);
// Off points have to be transformed anyway in case they're used by
// other ends of lines or triangles, so we have to check it here.
// Using getDrawingColor() checks for invisible, aspect-invisible, *and* off points
if( q != null && (!q.isUnpickable() || superpick) && !q.getDrawingColor(this).isInvisible())
theone = q;
}
}
return theone;
}
public void setPickingRadius(double r)
{
if(r > 1)
this.pickingRadius = (float)r;
}
//}}}
//{{{ pickAll3D
//##################################################################################################
/**
* Finds all points within the specified radius of the given coordinates.
* All coordinates are device coordinates -- i.e., coordinates in the transformed space.
* The units, therefore, are pixels.
* @return all the KPoints that were selected
*/
public Collection pickAll3D(double xcoord, double ycoord, double zcoord, boolean superpick, double radius)
{
// Iterate over all levels and all points in each level, searching for "the one"
int i, j, end_j; // loop over z-buffer
ArrayList zb; // == zbuffer[i], saves array lookups
KPoint p;
ArrayList found = new ArrayList();
double r2 = radius*radius;
// Note: looping front to back, rather than back to front as in render()
// start layer == (int)(TOP_LAYER*(zcoord-clipBack)/clipDepth)
final int frontLayer = TOP_LAYER, backLayer = 0;
for(i = frontLayer; i >= backLayer; i--)
{
zb = zbuffer[i];
end_j = zb.size();
for(j = 0; j < end_j; j++)
{
p = (KPoint)zb.get(j);
double dx = p.getDrawX() - xcoord;
double dy = p.getDrawY() - ycoord;
double dz = p.getDrawZ() - zcoord;
// Using getDrawingColor() checks for invisible, aspect-invisible, *and* off points
if((dx*dx + dy*dy + dz*dz) <= r2 && (!p.isUnpickable() || superpick) && !p.getDrawingColor(this).isInvisible())
found.add(p);
}
}
return found;
}
//}}}
//{{{ pickAll2D
//##################################################################################################
/**
* Finds all points within the specified radius of the given x-y coordinates,
* regardless of the z coordinate.
* All coordinates are device coordinates -- i.e., coordinates in the transformed space.
* The units, therefore, are pixels.
* @return all the KPoints that were selected
*/
public Collection pickAll2D(double xcoord, double ycoord, boolean superpick, double radius)
{
// Iterate over all levels and all points in each level, searching for "the one"
int i, j, end_j; // loop over z-buffer
ArrayList zb; // == zbuffer[i], saves array lookups
KPoint p;
ArrayList found = new ArrayList();
double r2 = radius*radius;
// Note: looping front to back, rather than back to front as in render()
// start layer == (int)(TOP_LAYER*(zcoord-clipBack)/clipDepth)
final int frontLayer = TOP_LAYER, backLayer = 0;
for(i = frontLayer; i >= backLayer; i--)
{
zb = zbuffer[i];
end_j = zb.size();
for(j = 0; j < end_j; j++)
{
p = (KPoint)zb.get(j);
double dx = p.getDrawX() - xcoord;
double dy = p.getDrawY() - ycoord;
// Using getDrawingColor() checks for invisible, aspect-invisible, *and* off points
if((dx*dx + dy*dy) <= r2 && (!p.isUnpickable() || superpick) && !p.getDrawingColor(this).isInvisible())
found.add(p);
}
}
return found;
}
//}}}
//{{{ getNumberPainted, getCanvasSize, setTransparentBackground
//##################################################################################################
/** Calculates the number of KPoint objects that were "painted" in the last cycle. */
public int getNumberPainted()
{
int num = 0;
for(int i = 0; i < zbuffer.length; i++) num += zbuffer[i].size();
return num;
}
/** Returns the size of the last rendering operation. */
public Dimension getCanvasSize()
{
return new Dimension(canvasRect.width, canvasRect.height);
}
/**
* Makes the background be rendered as transparent for the next pass ONLY.
* This is useful for certain export features that don't want a black/white
* box hanging around behind the image.
*/
public void setTransparentBackground()
{ this.transparentBackground = true; }
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/RingPoint.java 0000644 0000000 0000000 00000014037 11531212670 020457 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* RingPoint
represents a screen-oriented annulus around a particular point.
* Ring size scales up and down like balls; i.e. it's a real size rather than a display size.
* It implements Mage ringlists.
*
*
Begun on Sat Apr 27 11:02:02 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class RingPoint extends AbstractPoint // implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
public float r0 = 0f, r = 0f; // radius ( r0 >= 0 => use list radius )
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a new data point representing one end of a line.
*
* @param list the list that contains this point
* @param label the pointID of this point
*/
public RingPoint(KList list, String label)
{
super(list, label);
}
//}}}
//{{{ get/setRadius
//##################################################################################################
/** Sets the radius of this point, if applicable */
public void setRadius(float radius)
{
if(radius >= 0) r0 = radius;
}
public float getRadius()
{ return r0; }
//}}}
//{{{ signalTransform
//##################################################################################################
/** Rings require a zoom factor, so this throws UnsupportedOperationException */
public void signalTransform(Engine engine, Transform xform)
{ throw new UnsupportedOperationException(this.getClass()+".signalTransform() requires a zoom factor"); }
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
// Don't call super.signalTransform() b/c we do it all here
if(r0 <= 0 && parent != null) r = (float)(parent.radius * zoom);
else r = (float)(r0 * zoom);
xform.transform(this, engine.work1);
setDrawXYZ(engine.work1);
if(engine.usePerspective)
{
// multiply radius by perspDist/(perspDist - originalZ)
// This is a very subtle effect -- barely notable.
r *= (engine.perspDist) / (engine.perspDist - z);
// This is the old code -- seems to be wrong. (031017)
//r *= (engine.perspDist + z) / engine.perspDist;
}
// Can't handle (artificial) thickness cues here
// b/c engine.widthCue isn't set yet.
engine.addPaintable(this, z);
// Rings don't do line shortening around them -- the point is to see the center.
}
//}}}
//{{{ isPickedBy
//##################################################################################################
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{
float dx, dy;
dx = (x - xx);
dy = (y - yy);
//if( Math.abs( Math.sqrt(dx*dx + dy*dy) - r ) <= radius ) return this;
float sqDist = (dx*dx + dy*dy);
float minDist = r - radius; if(minDist > 0) minDist *= minDist;
float maxDist = r + radius; maxDist *= maxDist;
if(minDist <= sqDist && sqDist <= maxDist) return this;
else return null;
}
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
int alpha = (parent == null ? 255 : parent.alpha);
Paint paint = maincolor.getPaint(engine.backgroundMode, 1, engine.colorCue, alpha);
// For now we ignore the linewidth issue
double d = 2*r;
engine.painter.drawOval(paint, calcLineWidth(engine), engine.widthCue, x, y, z, d, d);
}
//}}}
//{{{ calcLineWidth
//##################################################################################################
// Default way of finding the right line width to use, given the settings in the engine
int calcLineWidth(Engine engine)
{
if(engine.thinLines) return 1;
else if(parent != null) return parent.width;
else return 2;
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/AHEImpl.java 0000644 0000000 0000000 00000004403 11531212670 017761 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* AHEImpl
(Abstract Hierarchy Element implementation)
* provides the basic services used by AGEs and most KPoints.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 10:50:32 EDT 2002
*/
abstract public class AHEImpl implements AHE
{
//{{{ Variable definitions
//##################################################################################################
String name = "";
//}}}
//{{{ get/setName, toString
//##################################################################################################
/** Gets the name of this element */
public String getName()
{ return name; }
/** Sets the name of this element */
public void setName(String nm)
{ name = nm; }
/** Gets the name of this element (same as getName()
*/
public String toString()
{ return getName(); }
//}}}
//{{{ getKinemage
//##################################################################################################
/** Retrieves the Kinemage object holding this element, or null if none. */
public Kinemage getKinemage()
{
AGE owner = getOwner();
if(owner == null) return null;
else return owner.getKinemage();
}
//}}}
//{{{ isVisible, isTotallyOn
//##################################################################################################
/** Indicates whether this element will actually be painted (i.e., is it and all its parents on?) */
public boolean isVisible()
{ return (getOwner().isVisible() && isOn()); }
/** Returns true iff this element is On, it's owner is On, it's owner's owner is On, and so on */
public boolean isTotallyOn()
{
if(this.getOwner() == null) return this.isOn();
else return (this.isOn() && this.getOwner().isTotallyOn());
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/ParaParams.java 0000644 0000000 0000000 00000021746 11531212670 020602 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* ParaParams
manages switching a kinemage in and out of
* parallel coordinates display of its high dimensional data.
*
*
Copyright (C) 2006 by Ian W. Davis. All rights reserved.
*
Begun on Fri Nov 17 11:35:12 EST 2006
*/
public class ParaParams //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
Kinemage kin;
int numDim;
double[] min;
double[] max;
double[] range;
Map normalChildren;
Map parallelChildren;
KingView normalView;
KingView parallelView;
boolean inParallelMode = false;
KGroup axisGroup = null;
//}}}
//{{{ Constructor(s)
//##############################################################################
public ParaParams(Kinemage kin)
{
super();
this.kin = kin;
this.numDim = Math.max(2, kin.dimensionNames.size()); // if less, denom -> 0
this.min = new double[numDim];
this.max = new double[numDim];
this.range = new double[numDim];
List minmax = kin.dimensionMinMax;
for(int i = 0; i < numDim; i++)
{
if(minmax.size() > 2*i) min[i] = ((Number) minmax.get(2*i)).doubleValue();
else min[i] = 0;
if(minmax.size() > 2*i + 1) max[i] = ((Number) minmax.get(2*i + 1)).doubleValue();
else max[i] = 360;
range[i] = max[i] - min[i];
}
this.normalChildren = new HashMap();
this.parallelChildren = new HashMap();
this.normalView = new KingView(kin); // will never be used
this.parallelView = new KingView(kin);
parallelView.setCenter(0.5f, 0.5f, 0f);
parallelView.setSpan(1.2f);
parallelView.setName("PC Overview");
kin.addView((KingView) parallelView.clone());
kin.signal.signalKinemage(kin, KinemageSignal.STRUCTURE);
}
//}}}
//{{{ getMin/Max/Range/NumDim
//##############################################################################
/** Returns the minimum value to be shown on axis i */
public double getMin(int dimension_i)
{ return this.min[dimension_i]; }
/** Returns the maximum value to be shown on axis i */
public double getMax(int dimension_i)
{ return this.max[dimension_i]; }
/** Returns max[i] - min[i] */
public double getRange(int dimension_i)
{ return this.range[dimension_i]; }
/** Returns the total number of dimension axes to be displayed */
public int getNumDim()
{ return this.numDim; }
//}}}
//{{{ swap
//##############################################################################
/** Toggles between "normal" and parallel coordinates modes. */
public void swap()
{
if(inParallelMode) fromParallelCoords();
else toParallelCoords();
inParallelMode = !inParallelMode;
}
//}}}
//{{{ toParallelCoords
//##############################################################################
void toParallelCoords()
{
normalChildren.clear(); // to remove any stale entries
for(Iterator ki = kin.iterator(); ki.hasNext(); )
{
KGroup g = (KGroup) ki.next();
for(Iterator gi = g.iterator(); gi.hasNext(); )
{
KSubgroup s = (KSubgroup) gi.next();
for(Iterator si = s.iterator(); si.hasNext(); )
{
KList l = (KList) si.next();
List newChildren = (List) parallelChildren.get(l);
if(newChildren == null)
{
newChildren = makeParallelPlot(l);
parallelChildren.put(l, newChildren);
}
normalChildren.put(l, l.children);
l.children = newChildren;
}
}
}
makeParallelAxes();
kin.calcSize(); // bounding box, etc. has changed!
normalView = kin.getCurrentView();
parallelView.setViewingAxes(normalView.getViewingAxes());
parallelView.selectedFromMenu(null);
}
//}}}
//{{{ fromParallelCoords
//##############################################################################
void fromParallelCoords()
{
parallelChildren.clear(); // to remove any stale entries
for(Iterator ki = kin.iterator(); ki.hasNext(); )
{
KGroup g = (KGroup) ki.next();
for(Iterator gi = g.iterator(); gi.hasNext(); )
{
KSubgroup s = (KSubgroup) gi.next();
for(Iterator si = s.iterator(); si.hasNext(); )
{
KList l = (KList) si.next();
List newChildren = (List) normalChildren.get(l);
if(newChildren == null)
{
newChildren = new ArrayList();
normalChildren.put(l, newChildren);
}
parallelChildren.put(l, l.children);
l.children = newChildren;
}
}
}
kin.calcSize(); // bounding box, etc. has changed!
parallelView = kin.getCurrentView();
normalView.setViewingAxes(parallelView.getViewingAxes());
normalView.selectedFromMenu(null);
}
//}}}
//{{{ makeParallelPlot
//##############################################################################
List makeParallelPlot(KList list)
{
ArrayList out = new ArrayList();
for(Iterator iter = list.iterator(); iter.hasNext(); )
{
KPoint normalPt = (KPoint) iter.next();
float[] allCoords = normalPt.getAllCoords();
if(allCoords == null) continue;
if(normalPt instanceof MarkerPoint
|| normalPt instanceof ProxyPoint
|| normalPt instanceof VectorPoint
|| normalPt instanceof TrianglePoint) continue;
ParaPoint ppLast = null;
for(int i = 0; i < allCoords.length; i++)
{
ParaPoint pp = new ParaPoint(normalPt, i, ppLast, this);
out.add(pp);
ppLast = pp;
}
}
return out;
}
//}}}
//{{{ makeParallelAxes
//##############################################################################
void makeParallelAxes()
{
boolean newAxes = (axisGroup == null);
if(newAxes)
{
axisGroup = new KGroup(kin, "PC axes");
kin.add(axisGroup);
}
else axisGroup.children.clear();
KSubgroup subgroup = new KSubgroup(axisGroup, "");
subgroup.setHasButton(false);
axisGroup.add(subgroup);
KList axisList = new KList(subgroup, "axes");
axisList.setType(KList.VECTOR);
axisList.setColor(KPalette.white);
subgroup.add(axisList);
KList labelList = new KList(subgroup, "labels");
labelList.setType(KList.LABEL);
labelList.setColor(KPalette.white);
subgroup.add(labelList);
String[] dimNames = (String[]) kin.dimensionNames.toArray(new String[numDim]);
DecimalFormat df = new DecimalFormat("0.###");
for(int i = 0; i < numDim; i++)
{
VectorPoint v1 = new VectorPoint(axisList, "", null);
v1.setXYZ((double)i / (double)(numDim-1), 0, 0);
v1.setUnpickable(true);
axisList.add(v1);
VectorPoint v2 = new VectorPoint(axisList, "", v1);
v2.setXYZ((double)i / (double)(numDim-1), 1, 0);
v2.setUnpickable(true);
axisList.add(v2);
LabelPoint l1 = new LabelPoint(labelList, dimNames[i]);
l1.setXYZ((double)i / (double)(numDim-1), 1.05, 0);
l1.setUnpickable(true);
l1.setHorizontalAlignment(LabelPoint.CENTER);
labelList.add(l1);
l1 = new LabelPoint(labelList, df.format(max[i]));
l1.setXYZ((double)i / (double)(numDim-1), 1.02, 0);
l1.setUnpickable(true);
l1.setHorizontalAlignment(LabelPoint.CENTER);
labelList.add(l1);
l1 = new LabelPoint(labelList, df.format(min[i]));
l1.setXYZ((double)i / (double)(numDim-1), -0.03, 0);
l1.setUnpickable(true);
l1.setHorizontalAlignment(LabelPoint.CENTER);
labelList.add(l1);
}
kin.signal.signalKinemage(kin, KinemageSignal.STRUCTURE | KinemageSignal.APPEARANCE);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KPaint.java 0000644 0000000 0000000 00000047463 11531212670 017745 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* KPaint
encapsulates all the data about a single
* named Mage color, like "red" or "lilactint" or "invisible".
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Wed Jun 25 14:37:56 EDT 2003
*/
abstract public class KPaint //extends ... implements ...
{
//{{{ Constants
/** The nominal "black" color to be used as a background, etc. */
public static final Color black = new Color(0.00f, 0.00f, 0.00f);
/** The nominal "white" color to be used as a background, etc. */
public static final Color white = new Color(1.00f, 1.00f, 1.00f);
//public static final Color white = new Color(0.95f, 0.95f, 0.95f);
/** The number of different depth-cueing levels available */
public static final int COLOR_LEVELS = 16;
/**
* The minimum value multiplier on a black background.
* Smaller numbers mean we fade closer to black before clipping.
*/
static final float BVAL = 0.36f;
/** The minimum value multiplier on a white background. */
static final float WVAL = 0.40f;
/** The minimum saturation multiplier on a white background. */
static final float WSAT = 0.36f;
/** Shading parameters for ribbons / triangles */
static final double AMBIENT_COEFF = 0.4;
static final double DIFFUSE_COEFF = 0.6;
public static final int BLACK_COLOR = 0;
public static final int WHITE_COLOR = 1;
public static final int BLACK_MONO = 2;
public static final int WHITE_MONO = 3;
public static final int N_BACKGROUNDS = 4;
//}}}
//{{{ Constants for ribbon shading
/** Background colors for ribbon shading calcs. */
static final Color[][] SHADE_BACKGROUNDS = new Color[N_BACKGROUNDS][COLOR_LEVELS];
static
{
Color[] background = new Color[COLOR_LEVELS];
for(int i = 0; i < COLOR_LEVELS; i++)
background[i] = black;
SHADE_BACKGROUNDS[BLACK_COLOR] = background;
SHADE_BACKGROUNDS[BLACK_MONO] = background;
// Instead of blending toward black, we're going to blend
// toward black depthcued on a white background:
// XXX: needs to be updated to use KPaint.white ...
float[] values = interpolate(1-WVAL, 0, COLOR_LEVELS);
background = new Color[COLOR_LEVELS];
for(int i = 0; i < COLOR_LEVELS; i++)
background[i] = new Color(Color.HSBtoRGB(0f, 0f, values[i]));
SHADE_BACKGROUNDS[WHITE_COLOR] = background;
SHADE_BACKGROUNDS[WHITE_MONO] = background;
}
//}}}
//{{{ Variable definitions
//##################################################################################################
String name;
KPaint aliasOf;
boolean isInvisible;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor -- use create___() functions instead
*/
KPaint()
{
}
//}}}
//{{{ createHSV, getHSB
//##################################################################################################
/**
* Creates a new color definition based on hue (0-360), saturation (0-100),
* and relative value (0-100; usually 75-100).
*/
static public KPaint createHSV(String name, float hue, float blackSat, float whiteSat, float blackVal, float whiteVal)
{
if(name == null)
throw new NullPointerException("Must give paint a name");
HeavyKPaint p = new HeavyKPaint();
p.name = name;
p.aliasOf = null;
p.paints = new Paint[N_BACKGROUNDS][];
p.paintsBackup = p.paints;
p.isInvisible = false;
hue /= 360f;
blackSat /= 100f;
whiteSat /= 100f;
blackVal /= 100f;
whiteVal /= 100f;
// value decreases going back
Color[] bcolors = new Color[COLOR_LEVELS];
float[] bvalues = interpolate(BVAL, 1, COLOR_LEVELS);
for(int i = 0; i < COLOR_LEVELS; i++)
bcolors[i] = getHSB(hue, blackSat, bvalues[i]*blackVal);
// value increases, saturation decreases going back
Color[] wcolors = new Color[COLOR_LEVELS];
float[] wsats = interpolate(WSAT, 1, COLOR_LEVELS);
// Low end is a blend between specified value and pure white value
float[] wvalues = interpolate( (WVAL*whiteVal + (1f-WVAL)*1f) , whiteVal, COLOR_LEVELS);
for(int i = 0; i < COLOR_LEVELS; i++)
wcolors[i] = getHSB(hue, wsats[i]*whiteSat, wvalues[i]);
p.paints[BLACK_COLOR] = bcolors;
p.paints[WHITE_COLOR] = wcolors;
p.paints[BLACK_MONO] = makeMonochrome((Color[])p.paints[BLACK_COLOR]);
p.paints[WHITE_MONO] = makeMonochrome((Color[])p.paints[WHITE_COLOR]);
return p;
}
static private Color getHSB(float hue, float sat, float val)
{ return new Color(Color.HSBtoRGB(hue, sat, val)); }
//}}}
//{{{ createLightweightHSV
//##################################################################################################
/**
* Creates a new color definition based on hue (0-360), saturation (0-100),
* and relative value (0-100; usually 75-100).
*/
static public KPaint createLightweightHSV(String name, float bHue, float bSat, float bVal, float wHue, float wSat, float wVal)
{
if(name == null)
throw new NullPointerException("Must give paint a name");
KPaint p = new LightKPaint(bHue / 360f, bSat / 100f, bVal / 100f,
wHue / 360f, wSat / 100f, wVal / 100f);
p.name = name;
p.aliasOf = null;
p.isInvisible = false;
return p;
}
//}}}
//{{{ createSolid
//##################################################################################################
/**
* Creates a paint that is the same regardless of shading, depth-cueing, etc.
*/
static public KPaint createSolid(String name, Paint solid)
{
if(name == null)
throw new NullPointerException("Must give paint a name");
if(solid == null)
throw new NullPointerException("Must provide a valid Paint");
HeavyKPaint p = new HeavyKPaint();
p.name = name;
p.aliasOf = null;
p.paints = new Paint[N_BACKGROUNDS][COLOR_LEVELS];
p.paintsBackup = p.paints;
p.isInvisible = false;
for(int i = 0; i < N_BACKGROUNDS; i++)
for(int j = 0; j < COLOR_LEVELS; j++)
p.paints[i][j] = solid;
return p;
}
//}}}
//{{{ createAlias, createInvisible
//##################################################################################################
/**
* Creates a new color that is simply an alias to some existing color.
*/
static public KPaint createAlias(String name, KPaint target)
{
if(name == null)
throw new NullPointerException("Must give paint a name");
if(target == null)
throw new NullPointerException("Must give paint alias an existing paint to reference");
HeavyKPaint t = (HeavyKPaint) target;
HeavyKPaint p = new HeavyKPaint();
p.name = name;
p.aliasOf = t;
p.paints = t.paints;
p.paintsBackup = p.paints;
p.isInvisible = t.isInvisible;
return p;
}
/**
* Create a color marked as invisible that is very
* distinctive if actually painted.
*/
static public KPaint createInvisible(String name)
{
Paint invis = new GradientPaint(0, 0, Color.red, 11, 3, Color.green, true);
KPaint p = createSolid(name, invis);
p.isInvisible = true;
return p;
}
//}}}
//{{{ getPaint(s)
//##################################################################################################
/**
* Returns the correct Paint object to use for rendering.
* Based on the value of dotprod, a simple
* lighting model (diffuse and ambient) is applied:
*
*
C = Fa*Lc*Oc + Fd*Lc*Oc*(On . -Ln)
*
*
where C is the resulting color, Fa and Fd are the ambient
* and diffuse lighting coefficients, Lc and Oc are color curves
* for the light source and the object, and Ln and On are normals
* for the light source and the object.
*
* These color objects are calculated on the fly rather than being cached.
*
* @param backgroundMode one of BLACK_COLOR, WHITE_COLOR, BLACK_MONO, or WHITE_MONO.
* @param dotprod the (normalized) dot product of the surface normal with the lighting vector.
* @param depth the depth cue number, from 0 (far away) to COLOR_LEVELS-1 (near by).
* @param alpha the transparency, from 0 (transparent) to 255 (opaque).
*/
public Paint getPaint(int backgroundMode, double dotprod, int depth, int alpha)
{
Paint basePaint = getPaint(backgroundMode, depth);
if(dotprod < 0) dotprod = -dotprod;
if(dotprod > 1) dotprod = 1;
if(dotprod == 1 && alpha == 255)
return basePaint;
try
{
double weight = AMBIENT_COEFF + (DIFFUSE_COEFF*dotprod);
return blendColors(
(Color)basePaint, weight,
SHADE_BACKGROUNDS[backgroundMode][depth], (1-weight),
alpha);
}
catch(ClassCastException ex)
{
// Cast will only fail for the Invisible color, which
// uses a gradient paint. BUT we should never be calling
// this method if we already know our paint is invisible!
return basePaint;
}
}
/**
* Returns the correct Paint object to use for rendering,
* assuming direct lighting of the surface and no transparency.
* @param backgroundMode one of BLACK_COLOR, WHITE_COLOR, BLACK_MONO, or WHITE_MONO.
* @param depth the depth cue number, from 0 (far away) to COLOR_LEVELS-1 (near by).
*/
abstract public Paint getPaint(int backgroundMode, int depth);
/**
* Returns the set of depth-cued Paint objects to use for rendering,
* indexed from 0 (far away) to COLOR_LEVELS-1 (near by),
* assuming direct lighting of the surface and no transparency.
* @param backgroundMode one of BLACK_COLOR, WHITE_COLOR, BLACK_MONO, or WHITE_MONO.
*/
abstract public Paint[] getPaints(int backgroundMode);
//}}}
//{{{ blendColors, makeMonochrome
//##################################################################################################
/**
* Returns a blend of two colors, weighted by the given coefficients.
* Alpha ranges from 0 (transparent) to 255 (opaque) and is not taken from either c1 or c2.
*/
private static Color blendColors(Color c1, double w1, Color c2, double w2, int alpha)
{
int red = (int)(c1.getRed()*w1 + c2.getRed()*w2);
int green = (int)(c1.getGreen()*w1 + c2.getGreen()*w2);
int blue = (int)(c1.getBlue()*w1 + c2.getBlue()*w2);
if(red < 0) red = 0;
else if(red > 255) red = 255;
if(green < 0) green = 0;
else if(green > 255) green = 255;
if(blue < 0) blue = 0;
else if(blue > 255) blue = 255;
return new Color(red, green, blue, alpha);
}
/**
* Duplicates an array of colors while translating each one into monochrome.
* The formula used was taken from the POV-Ray documentation:
* gray value = Red*29.7% + Green*58.9% + Blue*11.4%
.
* Presumably this roughly matches the response of B&W film,
* based on some articles I've read elsewhere.
*
See also http://www.poynton.com/notes/colour_and_gamma/GammaFAQ.html,
* which offers this equation: Y(709) = 0.2126*R + 0.7152*G + 0.0722*B.
* However, using it directly here would probably be out of context...
*/
private static Color[] makeMonochrome(Color[] src)
{
Color[] targ = new Color[src.length];
for(int i = 0; i < src.length; i++)
targ[i] = makeMonochrome(src[i]);
return targ;
}
/**
* Translates a color into monochrome.
* The formula used was taken from the POV-Ray documentation:
* gray value = Red*29.7% + Green*58.9% + Blue*11.4%
.
* Presumably this roughly matches the response of B&W film,
* based on some articles I've read elsewhere.
*
See also http://www.poynton.com/notes/colour_and_gamma/GammaFAQ.html,
* which offers this equation: Y(709) = 0.2126*R + 0.7152*G + 0.0722*B.
* However, using it directly here would probably be out of context...
*/
static Color makeMonochrome(Color sc)
{
float gray = (0.297f*sc.getRed() + 0.589f*sc.getGreen() + 0.114f*sc.getBlue()) / 255f;
if(gray < 0) gray = 0;
if(gray > 1) gray = 1;
return new Color(gray, gray, gray, sc.getAlpha()/255f);
}
//}}}
//{{{ interpolate
//##################################################################################################
/** Blends linearly from start to end, with steps-2 intervening steps. */
static float[] interpolate(double start, double end, int steps)
{
float[] result = new float[steps];
for(int i = 0; i < steps; i++)
{
double a = (double)i / (double)(steps-1);
result[i] = (float)((1-a)*start + a*end);
}
return result;
}
//}}}
//{{{ get{Black, White}Exemplar
//##################################################################################################
/**
* Returns the most typical paint for this named color.
* If this Paint is an instance of Color, the hue, saturation, and value
* can be fed back into createHSV to recreate this color (probably).
* Remember to convert from the [0,1] scale to the [0,360] / [0,100] scale!
*/
public Paint getBlackExemplar()
{ return getPaint(BLACK_COLOR, COLOR_LEVELS-1); }
/**
* Returns the most typical paint for this named color.
* If this Paint is an instance of Color, the hue, saturation, and value
* can be fed back into createHSV to recreate this color (probably).
* Remember to convert from the [0,1] scale to the [0,360] / [0,100] scale!
*/
public Paint getWhiteExemplar()
{ return getPaint(WHITE_COLOR, COLOR_LEVELS-1); }
//}}}
//{{{ isInvisible, isAlias, getAlias, toString
//##################################################################################################
/** Returns true iff objects of this color should not be rendered. */
public boolean isInvisible()
{ return isInvisible; }
/** Returns true iff this KPaint is just another name for some canonical KPaint. */
public boolean isAlias()
{ return aliasOf != null; }
/**
* Returns the KPaint that this object is an alias of.
* @throws UnsupportedOperationException if this object is not an alias.
*/
public KPaint getAlias()
{
if(aliasOf != null) return aliasOf;
else throw new UnsupportedOperationException(this+" is not an alias of some other KPaint");
}
/** Returns the name this KPaint was created with. Will never be null. */
public String toString()
{ return name; }
//}}}
//{{{ setContrast
//##################################################################################################
/**
* Set the relative contrast of the color palette.
* A contrast of less than 1.0 is flat, and greater than 1.0 is exagerated.
*
Adjustment is done as linear interpolation/extrapolation to a mid-level gray.
* See http://www.sgi.com/misc/grafica/interp/ or
* P. Haeberli and D. Voorhies. Image Processing by Linear Interpolation and
* Extrapolation. IRIS Universe Magazine No. 28, Silicon Graphics, Aug, 1994.
*
* Only implemented for HeavyKPaint.
*/
public void setContrast(double alpha) {}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
/** A lightweight paint class for user-defined colors. */
class LightKPaint extends KPaint //{{{
{
float bHue, bSat, bVal;
float wHue, wSat, wVal;
public LightKPaint(float bHue, float bSat, float bVal, float wHue, float wSat, float wVal)
{
super();
this.bHue = bHue;
this.wHue = wHue;
this.bSat = bSat;
this.wSat = wSat;
this.bVal = bVal;
this.wVal = wVal;
}
public Paint getPaint(int backgroundMode, int depth)
{
double modHue, modSat, modVal;
Color color;
// Interpolation coefficient determined by depth
double d = (double)depth / (double)(COLOR_LEVELS-1);
if(backgroundMode == WHITE_COLOR || backgroundMode == WHITE_MONO)
{
modHue = wHue;
// Saturation interpolated from sat*WSAT at the back to sat*1.0 at the front
modSat = wSat * ((1-d)*WSAT + (d)*1);
// Value interpolated from a blend of val and pure white at the back
// to plain old val at the front.
modVal = (1-d)*(WVAL*wVal + (1f-WVAL)*1f) + (d)*wVal;
}
else // BLACK_COLOR || BLACK_MONO
{
modHue = bHue;
// Saturation is unchanged
modSat = bSat;
// Value interpolated from val*BVAL at the back to val*1.0 at the front
modVal = bVal * ((1-d)*BVAL + (d)*1);
}
color = new Color(Color.HSBtoRGB((float) modHue, (float) modSat, (float) modVal));
if(backgroundMode == WHITE_MONO || backgroundMode == BLACK_MONO)
color = makeMonochrome(color);
return color;
}
public Paint[] getPaints(int backgroundMode)
{
Paint[] paints = new Paint[COLOR_LEVELS];
for(int i = 0; i < COLOR_LEVELS; i++)
paints[i] = getPaint(backgroundMode, i);
return paints;
}
}//}}}
/** A memory-intensive (~2500 bytes) paint class for built-in colors. */
class HeavyKPaint extends KPaint //{{{
{
Paint[][] paints;
Paint[][] paintsBackup; // Usually == to paints. See setContrast().
public Paint getPaint(int backgroundMode, int depth)
{
return paints[backgroundMode][depth];
}
public Paint[] getPaints(int backgroundMode)
{
return paints[backgroundMode];
}
public void setContrast(double alpha)
{
this.paints = new Paint[N_BACKGROUNDS][COLOR_LEVELS];
final double midgray = 0.5;
final double one_minus_alpha = 1.0 - alpha;
for(int i = 0; i < N_BACKGROUNDS; i++)
{
for(int j = 0; j < COLOR_LEVELS; j++)
{
Paint p = (Paint) paintsBackup[i][j];
if(p instanceof Color)
{
Color c = (Color) p;
float r = (float)(alpha * c.getRed()/255.0 + one_minus_alpha * midgray);
r = Math.max(Math.min(1, r), 0);
float g = (float)(alpha * c.getGreen()/255.0 + one_minus_alpha * midgray);
g = Math.max(Math.min(1, g), 0);
float b = (float)(alpha * c.getBlue()/255.0 + one_minus_alpha * midgray);
b = Math.max(Math.min(1, b), 0);
paints[i][j] = new Color(r, g, b);
}
else
{
paints[i][j] = p;
}
}
}
}
}//}}}
king-2.21.120420/king/1.x_src/king/core/TrianglePoint.java 0000644 0000000 0000000 00000022603 11531212670 021323 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.io.*;
//import java.text.*;
//import java.util.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* TrianglePoint
provides filled, shaded triangles for triangle lists and ribbon lists.
* In a list of N points, there are N - 2 triangles: 1-2-3, 2-3-4, 3-4-5, etc.
*
*
Begun on Mon Jun 24 21:09:57 EDT 2002
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*/
public class TrianglePoint extends AbstractPoint // implements ...
{
//{{{ Static fields
/** This bit is set if the point is followed by an 'L' or a 'D'; this triangle takes its normal from previous one */
//static final int LINETO_BIT = 0x00800000;
//}}}
//{{{ Variable definitions
//##################################################################################################
TrianglePoint from;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new data point representing one point of a triangle.
*
* @param list the list that contains this point
* @param label the pointID of this point
* @param start where this line is drawn from, or null if it's the starting point
*/
public TrianglePoint(KList list, String label, TrianglePoint start)
{
super(list, label);
setPrev(start);
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
// Don't call super.signalTransform() b/c we do it all here
xform.transform(this, engine.work1);
setDrawXYZ(engine.work1);
double triangleZ;
if(from == null || from.from == null) triangleZ = z;
//else triangleZ = (z + from.z + from.from.z)/3.0;
// Sort by average of two backmost vertices (midpoint of back edge).
// This helps for triangles "outlined" by vectors, because if the vectors will always
// sort in front of or equal to the triangle, so if they come after the triangles
// in the kinemage, they'll always be visible. Helps with e.g. protein ribbons.
else
{
if(z < from.z)
{
if(from.z < from.from.z) triangleZ = (z + from.z)/2.0;
else triangleZ = (z + from.from.z)/2.0;
}
else
{
if(z < from.from.z) triangleZ = (z + from.z)/2.0;
else triangleZ = (from.z + from.from.z)/2.0;
}
}
engine.addPaintable(this, triangleZ);
}
//}}}
//{{{ isPickedBy
//##################################################################################################
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{
if(objPick && from != null && from.from != null)
{
// deliberately using transformed coordinates, b/c they're projected flat
TrianglePoint A = this, B = from, C = from.from;
// first, make sure this is really a triangle, i.e. A != B != C
// otherwise, the signed area is always zero and it looks like we hit the edge
if(!((A.x == B.x && A.y == B.y) || (B.x == C.x && B.y == C.y) || (C.x == A.x && C.y == A.y)))
{
// then, do Andrew Ban's nifty intersection test
if(Builder.checkTriangle(xx, yy, A.x, A.y, B.x, B.y, C.x, C.y))
return this; // always this, so changing colors works as expected
/*{
float dx, dy, dA, dB, dC;
dx = xx - A.x; dy = yy - A.y; dA = dx*dx + dy*dy;
dx = xx - B.x; dy = yy - B.y; dB = dx*dx + dy*dy;
dx = xx - B.x; dy = yy - C.y; dC = dx*dx + dy*dy;
if(dA <= dB && dA <= dC) return A;
else if(dB <= dC) return B;
else return C;
}*/
}
}
return super.isPickedBy(xx, yy, radius, objPick);
}
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(from == null || from.from == null || maincolor.isInvisible()) return;
TrianglePoint A, B, C = from.from.from;
int colorCue = engine.colorCue;
// If this is a ribbon list, color the triangles in pairs (code for dependent triangles)
if((multi & SEQ_EVEN_BIT) != 0 && parent != null && parent.getType() == KList.RIBBON && C != null)
{
A = from;
B = from.from;
//C = from.from.from; -- already set
// We must match depth cueing AND lighting angle if we want ribbons to look uniform
// This is a huge pain in the butt -- code derived from signalTransform().
double triangleZ;
if(A.z < B.z)
{
if(B.z < C.z) triangleZ = (A.z + B.z)/2.0;
else triangleZ = (A.z + C.z)/2.0;
}
else
{
if(A.z < C.z) triangleZ = (A.z + B.z)/2.0;
else triangleZ = (B.z + C.z)/2.0;
}
// wrong, too simple:
//colorCue = (int)Math.floor(KPaint.COLOR_LEVELS * (triangleZ - engine.clipBack) / engine.clipDepth);
// right, multiple round off:
int i = (int)(engine.TOP_LAYER*(triangleZ-engine.clipBack)/engine.clipDepth);
colorCue = (KPaint.COLOR_LEVELS*i)/(engine.TOP_LAYER+1); // int division (floor)
if(colorCue < 0) colorCue = 0;
else if(colorCue >= KPaint.COLOR_LEVELS) colorCue = KPaint.COLOR_LEVELS-1;
}
// Otherwise, color each triangle individually (also independent triangles in ribbons)
else
{
A = this;
B = from;
C = from.from;
//colorCue = engine.colorCue; -- already set
}
// Do dot product of surface normal with lighting vector
// to determine diffuse lighting.
//engine.work1.likeVector(B, A);
engine.work1.setXYZ( A.getDrawX()-B.getDrawX(), A.getDrawY()-B.getDrawY(), A.getDrawZ()-B.getDrawZ() );
//engine.work2.likeVector(B, C);
engine.work2.setXYZ( C.getDrawX()-B.getDrawX(), C.getDrawY()-B.getDrawY(), C.getDrawZ()-B.getDrawZ() );
engine.work1.cross(engine.work2).unit();
double dotprod = engine.work1.dot(engine.lightingVector);
int alpha = (parent == null ? 255 : parent.alpha);
Paint paint = maincolor.getPaint(engine.backgroundMode, dotprod, colorCue, alpha);
engine.painter.paintTriangle(paint,
x, y, z,
from.x, from.y, from.z,
from.from.x, from.from.y, from.from.z
);
}
//}}}
//{{{ get/setPrev(), isBreak()
//##################################################################################################
/**
* Sets the point that precedes this one.
* This matters to "chainable" points, like vectors and triangles.
* For other points, it does nothing.
* @param pt the point preceding this one in seqence
*/
public void setPrev(KPoint pt)
{
super.setPrev(pt);
from = (TrianglePoint)pt;
}
/**
* Gets the point preceding this one in the chain.
* @return the preceding point, or null if (a) this is a break in the chain or (b) this is not a chainable point type.
*/
public KPoint getPrev()
{ return from; }
/**
* True iff this is a chainable point type (e.g. vector, triangle) AND there is a chain break.
*/
public boolean isBreak()
{ return (from == null); }
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/DotPoint.java 0000644 0000000 0000000 00000004717 11531212670 020312 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* DotPoint
represents a contact dot or other small point.
* These dots are not depth-cued by size, though the size can be set at time of creation.
* "Dots" are actually square, so a radius between 1 and 3 is probably desireable.
*
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 12:57:57 EDT 2002
*/
public class DotPoint extends AbstractPoint // implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a new data point representing a "dot".
*
* @param list the list that contains this point
* @param label the pointID of this point
*/
public DotPoint(KList list, String label)
{
super(list, label);
}
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
Paint paint = maincolor.getPaint(engine.backgroundMode, engine.colorCue);
int width = calcLineWidth(engine);
engine.painter.paintDot(paint, x, y, z, width);
}
//}}}
//{{{ calcLineWidth
//##################################################################################################
// Default way of finding the right line width to use, given the settings in the engine
// Dots never do depth cueing by width, because big square dots look crappy.
int calcLineWidth(Engine engine)
{
if(engine.thinLines) return 1;
else if(parent != null) return parent.width;
else return 2;
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/BallPoint.java 0000644 0000000 0000000 00000011350 11531212670 020425 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* BallPoint
represents a 3-D sphere.
* It implements Mage balllists.
*
*
Begun on Sat Apr 27 11:02:02 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class BallPoint extends RingPoint // implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a new data point representing one end of a line.
*
* @param list the list that contains this point
* @param label the pointID of this point
*/
public BallPoint(KList list, String label)
{
super(list, label);
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
// RingPoint signal transform handles most stuff
super.signalTransform(engine, xform, zoom);
// We still need to ask for line shortening, though
// Otherwise we create gaps around lines when our pointmaster is off.
// If ball is translucent, we should see line going to its center (?)
if(!this.getDrawingColor(engine).isInvisible() && (parent == null || parent.alpha > 192)) engine.addShortener(this, r);
}
//}}}
//{{{ isPickedBy
//##################################################################################################
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{
// We have this goofy call to the AbstractPoint implementation
// because Java doesn't allow super.super.foo()
return _isPickedBy(xx, yy, Math.max(radius, r), objPick);
// Balls should always act in "object pick" mode
//if(objPick) return super.isPickedBy(xx, yy, Math.max(radius, r), objPick);
//else return super.isPickedBy(xx, yy, radius, objPick);
}
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
int alpha = (parent == null ? 255 : parent.alpha);
Paint paint = maincolor.getPaint(engine.backgroundMode, 1, engine.colorCue, alpha);
// We *can* do extra depth cueing hints for balls, but I prefer not to.
// It works for small, isolated balls (e.g. waters), but it is confusing
// and downright misleading when many balls are close together, because
// the sizes of the balls are consistently and substantially inflated.
//
// We have to do this here b/c now widthCue is set
//if(engine.cueThickness) r *= KPalette.widthScale[ engine.widthCue ];
engine.painter.paintBall(paint, x, y, z, r, ((parent.flags & KList.NOHILITE) == 0));
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/JoglPainter.java 0000644 0000000 0000000 00000041204 11531212670 020760 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*; // for GLUT
//}}}
/**
* JoglPainter
is a hardware-accelerated Painter that uses
* the JOGL Java bindings for OpenGL.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Sat Jun 5 16:15:26 EDT 2004
*/
public class JoglPainter implements Painter
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
GL gl;
GLU glu;
GLUT glut;
Rectangle clipRgn = new Rectangle();
int currFont = GLUT.BITMAP_HELVETICA_12;
int[] xPoints = new int[6];
int[] yPoints = new int[6];
float[] circle4, circle8, circle16, circle32;
//}}}
//{{{ Constructor(s)
//##############################################################################
public JoglPainter(GLAutoDrawable drawable)
{
super();
gl = drawable.getGL();
//glu = drawable.getGLU();
glu = new GLU();
glut = new GLUT();
// This is necessary for antialiasing, but also for transparent objects.
gl.glEnable(gl.GL_BLEND);
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);
// Antialiasing for points and lines.
// Almost everything we draw is done as polygons, so this doesn't help.
//gl.glEnable(gl.GL_POINT_SMOOTH);
//gl.glEnable(gl.GL_LINE_SMOOTH);
// Antialiasing doesn't work for polygons (easily).
// Best bet is to render multiple times with slight offset to accum. buffer.
// See notes in JoglCanvas.
// THIS CODE DOESN"T WORK:
//gl.glBlendFunc(gl.GL_SRC_ALPHA_SATURATE, gl.GL_ONE);
//gl.glEnable(gl.GL_POLYGON_SMOOTH);
//gl.glDisable(gl.GL_DEPTH_TEST);
circle4 = makeCircle(4);
circle8 = makeCircle(8);
circle16 = makeCircle(16);
circle32 = makeCircle(32);
}
//}}}
//{{{ makeCircle, fillOval, drawOval
//##############################################################################
float[] makeCircle(int nVertices)
{
float[] c = new float[2*nVertices];
for(int i = 0; i < nVertices; i++)
{
double angle = 2 * Math.PI * (double)i / (double)nVertices;
// The /2 is a correction for using diameter instead of radius in fillOval()
c[2*i] = (float)(Math.cos(angle) / 2);
c[2*i+1] = (float)(Math.sin(angle) / 2);
}
return c;
}
void fillOval(double x, double y, double width, double height)
{
float[] circle;
double diam = (width > height ? width : height);
if(diam <= 3) circle = circle4;
else if(diam <= 8) circle = circle8;
else if(diam <= 16) circle = circle16;
else circle = circle32;
double cx = x + width/2;
double cy = y + height/2;
gl.glBegin(gl.GL_POLYGON);
for(int i = 0; i < circle.length; i+=2)
{
gl.glVertex2i((int)(cx + width*circle[i]), -(int)(cy + height*circle[i+1]));
}
gl.glEnd();
}
void drawOval(double x, double y, double width, double height)
{
float[] circle;
double diam = (width > height ? width : height);
if(diam <= 3) circle = circle4;
else if(diam <= 8) circle = circle8;
else if(diam <= 16) circle = circle16;
else circle = circle32;
double cx = x + width/2;
double cy = y + height/2;
gl.glBegin(gl.GL_LINE_LOOP);
for(int i = 0; i < circle.length; i+=2)
{
gl.glVertex2i((int)(cx + width*circle[i]), -(int)(cy + height*circle[i+1]));
}
gl.glEnd();
}
//}}}
//{{{ drawLine, fillRect, drawRect
//##############################################################################
void drawLine(int x1, int y1, int x2, int y2)
{
gl.glBegin(gl.GL_LINES);
gl.glVertex2i(x1, -y1);
gl.glVertex2i(x2, -y2);
gl.glEnd();
}
void fillRect(int x, int y, int width, int height)
{
gl.glRecti(x, -y, x+width, -(y+height));
}
void drawRect(int x, int y, int width, int height)
{
gl.glBegin(gl.GL_LINE_LOOP);
gl.glVertex2i(x, -y);
gl.glVertex2i(x, -(y+height));
gl.glVertex2i(x+width, -(y+height));
gl.glVertex2i(x+width, -y);
gl.glEnd();
}
//}}}
//{{{ paintBall
//##################################################################################################
public void paintBall(Paint paint, double x, double y, double z, double r, boolean showHighlight)
{
int d = (int)(2.0*r + 0.5);
if(d < 2) d = 2; // make sure balls don't disappear
// one disk
setPaint(paint);
fillOval(x-r, y-r, d, d);
// Black rim, causes ~10% speed penalty but useful for visualization!
try
{
Color c = (Color) paint;
if(d >= 10 && c.getAlpha() == 255)
{
setPaint(KPaint.black); // wants to merge with the background
drawOval(x-r, y-r, d, d);
}
}
catch(ClassCastException ex)
{
ex.printStackTrace();
System.err.println("JoglPainter: tried painting with non-Color type of Paint");
}
// highlight
if(showHighlight)
{
double off = 0.5 * r;
d = (int)(0.3*r)+1;
setPaint(Color.white); // wants to be bright white no matter what
fillOval(x-off, y-off, d, d);
}
}
//}}}
//{{{ paintDot
//##################################################################################################
public void paintDot(Paint paint, double x, double y, double z, int width)
{
double off = width/2;
setPaint(paint);
if(width == 1)
fillRect((int)(x-off), (int)(y-off), width, width);
else
{
width += 1; // not big enough otherwise
fillOval(x-off, y-off, width, width);
}
}
//}}}
//{{{ paintLabel
//##################################################################################################
public void paintLabel(Paint paint, String label, double x, double y, double z)
{
setPaint(paint);
gl.glRasterPos2d(x, -y);
//glut.glutBitmapString(gl, currFont, label);
glut.glutBitmapString(currFont, label);
}
//}}}
//{{{ paintMarker
//##################################################################################################
public void paintMarker(Paint paint, double x, double y, double z, int width, int paintStyle)
{
int cx = (int)x, cy = (int)y;
int one = width, two = 2*width, three = 3*width, four = 4*width, five = 5*width,
six = 6*width, seven = 7*width, ten = 10*width, eleven = 11*width;
this.setPaint(paint);
// Large discs and boxes
if((paintStyle & MarkerPoint.BOX_L) != 0) this.fillRect(cx-five, cy-five, eleven, eleven);
else if((paintStyle & MarkerPoint.DISC_L) != 0) this.fillOval(cx-five, cy-five, eleven, eleven);
// Medium discs and boxes
if((paintStyle & MarkerPoint.BOX_M) != 0) this.fillRect(cx-three, cy-three, seven, seven);
else if((paintStyle & MarkerPoint.DISC_M) != 0) this.fillOval(cx-three, cy-three, seven, seven);
// Small discs and boxes
if((paintStyle & MarkerPoint.BOX_S) != 0) this.fillRect(cx-one, cy-one, three, three);
else if((paintStyle & MarkerPoint.DISC_S) != 0) this.fillOval(cx-one, cy-one, three, three);
// Crosses
if((paintStyle & MarkerPoint.CROSS_S) != 0) { this.drawLine(cx, cy-one, cx, cy+one); this.drawLine(cx-one, cy, cx+one, cy); }
if((paintStyle & MarkerPoint.CROSS_M) != 0) { this.drawLine(cx, cy-three, cx, cy+three); this.drawLine(cx-three, cy, cx+three, cy); }
if((paintStyle & MarkerPoint.CROSS_L) != 0) { this.drawLine(cx, cy-five, cx, cy+five); this.drawLine(cx-five, cy, cx+five, cy); }
if((paintStyle & MarkerPoint.CROSS_2) != 0)
{
this.drawLine(cx-one, cy-five, cx-one, cy+five); this.drawLine(cx+one, cy-five, cx+one, cy+five);
this.drawLine(cx-five, cy-one, cx+five, cy-one); this.drawLine(cx-five, cy+one, cx+five, cy+one);
}
// X's
if((paintStyle & MarkerPoint.X_S) != 0) { this.drawLine(cx-one, cy-one, cx+one, cy+one); this.drawLine(cx-one, cy+one, cx+one, cy-one); }
if((paintStyle & MarkerPoint.X_M) != 0) { this.drawLine(cx-three, cy-three, cx+three, cy+three); this.drawLine(cx-three, cy+three, cx+three, cy-three); }
if((paintStyle & MarkerPoint.X_L) != 0) { this.drawLine(cx-five, cy-five, cx+five, cy+five); this.drawLine(cx-five, cy+five, cx+five, cy-five); }
if((paintStyle & MarkerPoint.X_2) != 0)
{
this.drawLine(cx-four, cy-five, cx+five, cy+four); this.drawLine(cx-five, cy-four, cx+four, cy+five);
this.drawLine(cx-four, cy+five, cx+five, cy-four); this.drawLine(cx-five, cy+four, cx+four, cy-five);
}
// Squares
if((paintStyle & MarkerPoint.SQUARE_S) != 0) this.drawRect(cx-one, cy-one, two, two);
if((paintStyle & MarkerPoint.SQUARE_M) != 0) this.drawRect(cx-three, cy-three, six, six);
if((paintStyle & MarkerPoint.SQUARE_L) != 0) this.drawRect(cx-five, cy-five, ten, ten);
// Circles
if((paintStyle & MarkerPoint.RING_S) != 0) this.drawOval(cx-one, cy-one, two, two);
if((paintStyle & MarkerPoint.RING_M) != 0) this.drawOval(cx-three, cy-three, six, six);
if((paintStyle & MarkerPoint.RING_L) != 0) this.drawOval(cx-five, cy-five, ten, ten);
}
//}}}
//{{{ paintSphereDisk
//##################################################################################################
public void paintSphereDisk(Paint paint, double x, double y, double z, double r)
{
int d = (int)(2.0*r + 0.5);
if(d < 2) d = 2; // make sure balls don't disappear
// one disk
setPaint(paint);
fillOval(x-r, y-r, d, d);
}
//}}}
//{{{ paintTriangle
//##################################################################################################
public void paintTriangle(Paint paint,
double x1, double y1, double z1,
double x2, double y2, double z2,
double x3, double y3, double z3)
{
setPaint(paint);
gl.glBegin(GL.GL_TRIANGLES);
gl.glVertex2i((int)x1, -(int)y1);
gl.glVertex2i((int)x2, -(int)y2);
gl.glVertex2i((int)x3, -(int)y3);
gl.glEnd();
}
//}}}
//{{{ paintVector
//##################################################################################################
public void paintVector(Paint paint, int width, int widthCue,
double x1, double y1, double z1,
double x2, double y2, double z2)
{
setPaint(paint);
prettyLine((int)x1, (int)y1, (int)x2, (int)y2, KPalette.lineWidths[width-1][widthCue]);
}
//}}}
//{{{ prettyLine
//##################################################################################################
/** Draws a thick line with nice ends, using fillPolygon(). Slightly slower (30-35%) than fastLine(). */
void prettyLine(int x1, int y1, int x2, int y2, int width)
{
int s, e, abs_x2_x1, abs_y2_y1;
s = -width / 2; // Start offset
e = s + width; // End offset
abs_x2_x1 = Math.abs(x2 - x1);
abs_y2_y1 = Math.abs(y2 - y1);
// horizontal --
if( abs_x2_x1 > abs_y2_y1 )
{
// left to right
if( x1 < x2 )
{
xPoints[0] = x1 ; xPoints[1] = x1+s; xPoints[2] = x1; xPoints[3] = x2; xPoints[4] = x2-s; xPoints[5] = x2;
yPoints[0] = y1+s; yPoints[1] = y1; yPoints[2] = y1+e; yPoints[3] = y2+e; yPoints[4] = y2; yPoints[5] = y2+s;
}
// right to left
else
{
xPoints[0] = x1 ; xPoints[1] = x1-s; xPoints[2] = x1; xPoints[3] = x2; xPoints[4] = x2+s; xPoints[5] = x2;
yPoints[0] = y1+s; yPoints[1] = y1; yPoints[2] = y1+e; yPoints[3] = y2+e; yPoints[4] = y2; yPoints[5] = y2+s;
}
}
// vertical |
else
{
// top to bottom
if( y1 < y2 )
{
xPoints[0] = x1+s; xPoints[1] = x1; xPoints[2] = x1+e; xPoints[3] = x2+e; xPoints[4] = x2; xPoints[5] = x2+s;
yPoints[0] = y1 ; yPoints[1] = y1+s; yPoints[2] = y1; yPoints[3] = y2; yPoints[4] = y2-s; yPoints[5] = y2;
}
// bottom to top
else
{
xPoints[0] = x1+s; xPoints[1] = x1; xPoints[2] = x1+e; xPoints[3] = x2+e; xPoints[4] = x2; xPoints[5] = x2+s;
yPoints[0] = y1 ; yPoints[1] = y1-s; yPoints[2] = y1; yPoints[3] = y2; yPoints[4] = y2+s; yPoints[5] = y2;
}
}
gl.glBegin(GL.GL_POLYGON);
gl.glVertex2i((int)xPoints[0], -(int)yPoints[0]);
gl.glVertex2i((int)xPoints[1], -(int)yPoints[1]);
gl.glVertex2i((int)xPoints[2], -(int)yPoints[2]);
gl.glVertex2i((int)xPoints[3], -(int)yPoints[3]);
gl.glVertex2i((int)xPoints[4], -(int)yPoints[4]);
gl.glVertex2i((int)xPoints[5], -(int)yPoints[5]);
gl.glEnd();
}
//}}}
//{{{ drawOval
//##################################################################################################
public void drawOval(Paint paint, double x, double y, double z, double width, double height)
{
setPaint(paint);
drawOval((x - width/2), (y - height/2), width, height);
}
public void drawOval(Paint paint, int linewidth, int widthCue, double x, double y, double z, double width, double height)
{
setPaint(paint);
double startx = (x - width/2.0 - linewidth/2.0);
double starty = (y - height/2.0 - linewidth/2.0);
double diamx = ( width + linewidth);
double diamy = (height + linewidth);
for(int i = 0; i < linewidth; i++)
{
drawOval(startx, starty, diamx, diamy);
startx += 1;
starty += 1;
diamx -= 2;
diamy -= 2;
}
}
//}}}
//{{{ setFont, getLabelWidth/Ascent/Descent
//##############################################################################
public void setFont(Font f)
{
int sz = f.getSize();
if(sz <= 10) currFont = GLUT.BITMAP_HELVETICA_10;
else if(sz <= 14) currFont = GLUT.BITMAP_HELVETICA_12;
else currFont = GLUT.BITMAP_HELVETICA_18;
}
public int getLabelWidth(String s)
{ return glut.glutBitmapLength(currFont, s); }
public int getLabelAscent(String s)
{
if(currFont == GLUT.BITMAP_HELVETICA_10) return 10;
else if(currFont == GLUT.BITMAP_HELVETICA_12) return 12;
else if(currFont == GLUT.BITMAP_HELVETICA_18) return 18;
else return 1;
}
public int getLabelDescent(String s)
{ return getLabelAscent(s)/4; }
//}}}
//{{{ setPaint, setViewport, clearCanvas
//##############################################################################
void setPaint(Paint p)
{
try
{
Color c = (Color) p;
gl.glColor4f( c.getRed()/255f, c.getGreen()/255f, c.getBlue()/255f, c.getAlpha()/255f);
}
catch(ClassCastException ex)
{
ex.printStackTrace();
System.err.println("JoglPainter: tried painting with non-Color type of Paint");
}
}
public void setViewport(int x, int y, int width, int height)
{
clipRgn.setBounds(x, y, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
//glu.gluOrtho2D(0.0, width, -height, 0.0);
glu.gluOrtho2D(x, x+width, y-height, y);
gl.glViewport(x, y, width, height);
}
public void clearCanvas(Color c)
{
gl.glClearColor(c.getRed()/255f, c.getGreen()/255f, c.getBlue()/255f, c.getAlpha()/255f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KinfileParser.java 0000644 0000000 0000000 00000145401 11531212670 021304 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.util.SoftLog;
//}}}
/**
* KinfileParser
is a second-generation kinemage
* file loader. It contains the logic for interpretting all
* the tokens in the file, and returns one or more new kinemages
* when it's finished.
*
* Make sure to call initAll() on the resulting kinemages!
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Wed Apr 9 08:23:25 EDT 2003
*/
public class KinfileParser //extends ... implements ...
{
//{{{ Constants
public static final String DEFAULT_KINEMAGE_NAME = "Kinemage #";
static final String DEFAULT_GROUP_NAME = "";
static final String IMPLIED_GROUP_NAME = "(implied)";
static final int MAX_ERRORS_REPORTED = 30;
//}}}
//{{{ Variable definitions
//##################################################################################################
// Needed for basic function
LineNumberReader input;
KinfileTokenizer token;
// For tracking our position in the hierarchy
Kinemage kinemage = null;
KGroup group = null;
KSubgroup subgroup = null;
KList list = null;
// Info generated by this parser
Collection kinemages = new ArrayList();
StringBuffer atText = new StringBuffer();
Map viewMap = null; // created when kinemage is
// Used for implementing clone= and instance=
Map groupsByName = null; // created when kinemage is
Map subgroupsByName = null; // created when kinemage is
Map listsByName = null; // created when kinemage is
// Used for storing bondrots
TreeMap bondRots = null;
ArrayList closedBondRots = null;
int nonIntCount = 1;
// Used for high-dimensional kinemages
int groupDimension = 3;
int subgroupDimension = 3;
//}}}
//{{{ Constructor(s), parse
//##################################################################################################
/**
* Creates a new KinfileParser.
* Call parse() to read and interpret a file.
*/
public KinfileParser()
{
input = null;
token = null;
}
/**
* Reads and interprets the kinemage file supplied.
* Make sure to call initAll() on the resulting kinemages!
*
* @throws IOException if input stream throws any such exceptions during parsing
*/
public void parse(LineNumberReader in) throws IOException
{
input = in;
token = new KinfileTokenizer(input);
keywordLoop();
}
//}}}
//{{{ getKinemages, getText, getErrors, error, getCharsRead
//##################################################################################################
/**
* Returns an unmodifiable Collection of Kinemage objects contained in this file
*
* Make sure to call initAll() on the resulting kinemages!
*/
public Collection getKinemages()
{ return Collections.unmodifiableCollection(kinemages); }
/** Returns the concatenated result of all @text sections in this file */
public String getText()
{ return atText.toString(); }
void error(String msg)
{
SoftLog.err.println("[line "+(input.getLineNumber()+1)+"] "+msg);
}
/** Returns the number of characters read in thus far */
public long getCharsRead()
{
if(token != null) return token.getCharsRead();
else return 0;
}
//}}}
//{{{ keywordLoop
//##################################################################################################
void keywordLoop() throws IOException
{
String s;
while(!token.isEOF())
{
// Kinder to user to be case insensitive for keywords, at least
s = token.getString().toLowerCase();
if(!token.isKeyword())
{
error("Dangling token '"+s+"' outside any keywords");
token.advanceToKeyword();
}
// METADATA
else if(s.equals("@text")) doText();
else if(s.equals("@title")) doTitle();
else if(s.equals("@copyright")) doCopyright();
else if(s.equals("@caption")) doCaption();
else if(s.equals("@mage")) token.advanceToKeyword();//ignored
else if(s.equals("@prekin")) token.advanceToKeyword();//ignored
else if(s.equals("@pdbfile")) doPdbFile();
else if(s.equals("@command")) doCommand();
else if(s.equals("@dimensions")) doDimensions();
else if(s.equals("@dimension")) doDimensions(); //deprecated
else if(s.equals("@dimminmax")) doDimMinMax();
// VIEWS
else if(s.endsWith("viewid")) doViewID();
else if(s.endsWith("zoom")) doZoom();
else if(s.endsWith("span")) doSpan();
else if(s.endsWith("zslab")) doClip();
else if(s.endsWith("zclip")) doClip(); //deprecated
else if(s.endsWith("ztran")) token.advanceToKeyword(); //ignored
else if(s.endsWith("center")) doCenter();
else if(s.endsWith("matrix")) doMatrix();
else if(s.endsWith("axischoice")) doAxisChoice();
// DISPLAY OPTIONS
else if(s.equals("@whitebackground")) doWhiteBackground();
else if(s.equals("@whiteback")) doWhiteBackground(); //deprecated
else if(s.equals("@whitebkg")) doWhiteBackground(); //deprecated
else if(s.equals("@onewidth")) doOnewidth();
else if(s.equals("@thinline")) doThinline();
else if(s.equals("@perspective")) doPerspective();
else if(s.equals("@flat")) doFlat();
else if(s.equals("@flatland")) doFlat(); //deprecated
else if(s.equals("@xytranslation")) doFlat(); //deprecated
else if(s.equals("@listcolordominant")) doListColorDominant();
else if(s.equals("@listcolordom")) doListColorDominant(); //deprecated
else if(s.equals("@lens")) doLens();
// MASTERS, ASPECTS, AND COLORS
else if(s.endsWith("aspect")) doAspect();
else if(s.equals("@master")) doMaster();
else if(s.equals("@pointmaster")) doPointmaster();
else if(s.equals("@colorset")) doColorset();
else if(s.equals("@hsvcolor")) doHsvColor();
else if(s.equals("@hsvcolour")) doHsvColor();
// KINEMAGES, GROUPS, AND SUBGROUPS
else if(s.equals("@kinemage")) doKinemage();
else if(s.equals("@group")) doGroup();
else if(s.equals("@subgroup")) doSubgroup();
else if(s.equals("@set")) doSubgroup(); //deprecated
// LISTS
else if(s.equals("@vectorlist")) doList(KList.VECTOR);
else if(s.equals("@vector")) doList(KList.VECTOR); //deprecated
else if(s.equals("@labellist")) doList(KList.LABEL);
else if(s.equals("@label")) doList(KList.LABEL); //deprecated
else if(s.equals("@dotlist")) doList(KList.DOT);
else if(s.equals("@dot")) doList(KList.DOT); //deprecated
else if(s.equals("@ringlist")) doList(KList.RING);
else if(s.equals("@ring")) doList(KList.RING); //deprecated
else if(s.equals("@balllist")) doList(KList.BALL);
else if(s.equals("@ball")) doList(KList.BALL); //deprecated
else if(s.equals("@spherelist")) doList(KList.SPHERE);
else if(s.equals("@sphere")) doList(KList.SPHERE); //deprecated
else if(s.equals("@trianglelist")) doList(KList.TRIANGLE);
else if(s.equals("@triangle")) doList(KList.TRIANGLE); //deprecated
else if(s.equals("@ribbonlist")) doList(KList.RIBBON);
else if(s.equals("@ribbon")) doList(KList.RIBBON); //deprecated
else if(s.equals("@marklist")) doList(KList.MARK);
else if(s.equals("@mark")) doList(KList.MARK); //deprecated
else if(s.equals("@arrowlist")) doList(KList.ARROW);
else if(s.equals("@arrow")) doList(KList.ARROW); //deprecated
else
{
// In the future, we'd like to save this as-is.
error("Unrecognized keyword '"+s+"' will be ignored");
token.advanceToKeyword();
}
}//while not EOF
if(kinemage != null) kinemage.setBondRots(closeBondRots());
closedBondRots = new ArrayList();
}
//}}}
//{{{ doKinemage, checkKinemage
//##################################################################################################
void doKinemage() throws IOException
{
if (kinemage != null) {
kinemage.setBondRots(closeBondRots());
closedBondRots = new ArrayList();
}
kinemage = new Kinemage(DEFAULT_KINEMAGE_NAME+(kinemages.size()+1));
kinemages.add(kinemage);
group = null;
subgroup = null;
list = null;
viewMap = new HashMap();
groupsByName = new HashMap();
subgroupsByName = new HashMap();
listsByName = new HashMap();
bondRots = new TreeMap();
closedBondRots = new ArrayList();
token.advance();
while(!token.isEOF() && !token.isKeyword())
{
if(token.isInteger()) kinemage.setName(DEFAULT_KINEMAGE_NAME+token.getInt());
else if(token.isIdentifier()) kinemage.setName(token.getString()); //KiNG extension
else error("Unrecognized token '"+token.getString()+"' will be ignored");
token.advance();
}
}
void checkKinemage()
{
if(kinemage == null)
{
kinemage = new Kinemage(DEFAULT_KINEMAGE_NAME+(kinemages.size()+1));
kinemages.add(kinemage);
group = null;
subgroup = null;
list = null;
viewMap = new HashMap();
groupsByName = new HashMap();
subgroupsByName = new HashMap();
listsByName = new HashMap();
bondRots = new TreeMap();
closedBondRots = new ArrayList();
error("'"+token.getString()+"' was found before encountering @kinemage");
}
}
//}}}
//{{{ doGroup, checkGroup
//##################################################################################################
void doGroup() throws IOException
{
checkKinemage();
group = new KGroup(kinemage, DEFAULT_GROUP_NAME);
kinemage.add(group);
subgroup = null;
list = null;
groupDimension = 3;
token.advance();
// Entire @group must be on a single line
while(!token.isEOF() && !token.isKeyword() && !token.isBOL())
{
if(token.isIdentifier()) { group.setName(token.getString()); token.advance(); }
else if(token.isLiteral())
{
String s = token.getString();
if(s.equals("animate")) group.setAnimate(true);
else if(s.equals("2animate")) group.set2Animate(true);
else if(s.equals("off")) group.setOn(false);
else if(s.equals("dominant")) group.setDominant(true);
else if(s.equals("recessiveon")
|| s.equals("collapsable")
|| s.equals("collapsible")) group.setRecessiveOn(true);
else if(s.equals("nobutton")) group.setHasButton(false);
else if(s.equals("lens")) group.setLens(true);
else error("Unrecognized literal '"+s+"' will be ignored");
token.advance();
}
else if(token.isProperty())
{
String s = token.getString();
token.advance(); // past key
if(s.equals("master="))
{
if(token.isIdentifier())
{
kinemage.ensureMasterExists(token.getString());
group.addMaster(token.getString());
}
else error("master= was not followed by an identifier");
}
// Clone is a full or "deep" copy of the original
// Instance is a lightweight copy that uses the same underlying point data
else if(s.equals("clone=") || s.equals("instance="))
{
if(token.isIdentifier())
{
KGroup template = (KGroup) groupsByName.get(token.getString());
if(template != null) group.children = ((KGroup)template.clone(s.equals("clone="))).children;
}
else error(s+" was not followed by an identifier");
}
else if(s.equals("dimension="))
{
if(token.isInteger()) groupDimension = token.getInt();
else error(s+" was not followed by an integer");
}
else error("Unrecognized property '"+s+" "+token.getString()+"' will be ignored");
token.advance(); // past value
}
else { error("Unrecognized token '"+token.getString()+"' will be ignored"); token.advance(); }
}
// Done last, after we have our final name
groupsByName.put(group.getName(), group);
}
void checkGroup()
{
checkKinemage();
if(group == null)
{
group = new KGroup(kinemage, IMPLIED_GROUP_NAME);
group.setHasButton(false);
kinemage.add(group);
subgroup = null;
list = null;
groupDimension = 3;
}
}
//}}}
//{{{ doSubgroup, checkSubgroup
//##################################################################################################
void doSubgroup() throws IOException
{
checkGroup();
subgroup = new KSubgroup(group, DEFAULT_GROUP_NAME);
group.add(subgroup);
list = null;
subgroupDimension = 3;
token.advance();
// Entire @subgroup must be on a single line
while(!token.isEOF() && !token.isKeyword() && !token.isBOL())
{
if(token.isIdentifier()) { subgroup.setName(token.getString()); token.advance(); }
else if(token.isLiteral())
{
String s = token.getString();
if(s.equals("off")) subgroup.setOn(false);
else if(s.equals("dominant")) subgroup.setDominant(true);
else if(s.equals("recessiveon")
|| s.equals("collapsable")
|| s.equals("collapsible")) subgroup.setRecessiveOn(true);
else if(s.equals("nobutton")) subgroup.setHasButton(false);
else if(s.equals("lens")) subgroup.setLens(true);
else error("Unrecognized literal '"+s+"' will be ignored");
token.advance();
}
else if(token.isProperty())
{
String s = token.getString();
token.advance(); // past key
if(s.equals("master="))
{
if(token.isIdentifier())
{
kinemage.ensureMasterExists(token.getString());
subgroup.addMaster(token.getString());
}
else error("master= was not followed by an identifier");
}
// Clone is a full or "deep" copy of the original
// Instance is a lightweight copy that uses the same underlying point data
else if(s.equals("clone=") || s.equals("instance="))
{
if(token.isIdentifier())
{
KSubgroup template = (KSubgroup) subgroupsByName.get(token.getString());
if(template != null) subgroup.children = ((KSubgroup)template.clone(s.equals("clone="))).children;
}
else error(s+" was not followed by an identifier");
}
else if(s.equals("dimension="))
{
if(token.isInteger()) subgroupDimension = token.getInt();
else error(s+" was not followed by an integer");
}
else error("Unrecognized property '"+s+" "+token.getString()+"' will be ignored");
token.advance(); // past value
}
else { error("Unrecognized token '"+token.getString()+"' will be ignored"); token.advance(); }
}
// Done last, after we have our final name
subgroupsByName.put(subgroup.getName(), subgroup);
}
void checkSubgroup()
{
checkGroup();
if(subgroup == null)
{
subgroup = new KSubgroup(group, IMPLIED_GROUP_NAME);
subgroup.setHasButton(false);
group.add(subgroup);
list = null;
subgroupDimension = 3;
}
}
//}}}
//{{{ doList
//##################################################################################################
void doList(String kListType) throws IOException
{
checkSubgroup();
list = new KList(subgroup, DEFAULT_GROUP_NAME);
list.setType(kListType);
subgroup.add(list);
list.setDimension(3);
if(subgroupDimension != 3) list.setDimension(subgroupDimension);
else if(groupDimension != 3) list.setDimension(groupDimension);
if(kListType == KList.MARK) list.setStyle(MarkerPoint.SQUARE_L);
token.advance();
// Entire @list must be on a single line and may be terminated by the first point ID
boolean listIdFound = false;
while(!token.isEOF() && !token.isKeyword() && (!token.isIdentifier() || !listIdFound) && !token.isBOL())
{
if(token.isIdentifier())
{
list.setName(token.getString());
listIdFound = true;
token.advance();
}
else if(token.isLiteral())
{
String s = token.getString();
if(s.equals("off")) list.setOn(false);
else if(s.equals("nobutton")) list.setHasButton(false);
else if(s.equals("lens")) list.setLens(true);
else if(s.startsWith("nohi")) list.flags |= KList.NOHILITE;
// for doing bondrots
else if(s.endsWith("bondrot")) {
double angle = 0;
char firstChar = s.charAt(0);
int bondNum = -1;
if (Character.isDigit(firstChar)) {
bondNum = Character.getNumericValue(firstChar);
} else {
bondNum = nonIntCount;
nonIntCount++;
}
token.advance();
if(token.isNumber()) {
angle = token.getFloat();
} else {
error("angle for bondrot not number");
}
storeBondRot(bondNum, list.getName(), angle);
}
else error("Unrecognized literal '"+s+"' will be ignored");
token.advance();
}
else if(token.isProperty())
{
String s = token.getString();
token.advance(); // past key
if(s.equals("color=") || s.equals("colour="))
{
// e.g. red e.g. @colorset {HelixCap}
if( (token.isLiteral() || token.isIdentifier())
&& kinemage.getAllPaintMap().containsKey(token.getString()) )
{
list.setColor(kinemage.getPaintForName(token.getString()));
}
else error("color= was followed by unknown color '"+token.getString()+"'");
}
else if(s.equals("master="))
{
if(token.isIdentifier())
{
kinemage.ensureMasterExists(token.getString());
list.addMaster(token.getString());
}
else error("master= was not followed by an identifier");
}
// Clone is a full or "deep" copy of the original
else if(s.equals("clone="))
{
if(token.isIdentifier())
{
KList template = (KList) listsByName.get(token.getString());
if(template != null) list.children = ((KList)template.clone(true)).children;
}
else error("clone= was not followed by an identifier");
}
// Instance is a lightweight copy that uses the same underlying point data
else if(s.equals("instance="))
{
if(token.isIdentifier())
{
KList template = (KList) listsByName.get(token.getString());
if(template != null) list.setInstance(template);
}
else error("instance= was not followed by an identifier");
}
else if(s.equals("radius="))
{
if(token.isNumber()) list.setRadius(token.getFloat());
else error("radius= was not followed by a number");
}
else if(s.equals("angle="))
{
if(token.isNumber()) list.setAngle(token.getFloat());
else error("angle= was not followed by a number");
}
else if(s.equals("alpha=")) // opacity, from 1 (opaque) to 0 (transparent)
{
if(token.isNumber())
{
double alpha = token.getFloat();
if(alpha < 0) alpha = 0;
else if(alpha > 1) alpha = 1;
list.alpha = (int)(alpha*255 + 0.5);
}
else error("alpha= was not followed by a number");
}
else if(s.equals("width="))
{
if(token.isInteger()) list.setWidth(token.getInt());
else error("width= was not followed by an integer");
}
else if(s.equals("size="))
{
if(token.isInteger()) {} // useless property from legacy kins
else error("size= was not followed by an integer");
}
else if(s.equals("dimension="))
{
if(token.isInteger()) list.setDimension(token.getInt());
else error(s+" was not followed by an integer");
}
else error("Unrecognized property '"+s+" "+token.getString()+"' will be ignored");
token.advance(); // past value
}
else { error("Unrecognized token '"+token.getString()+"' will be ignored"); token.advance(); }
}
// Done last, after we have our final name
listsByName.put(list.getName(), list);
// Read in points until we hit another keyword or EOF
KPoint prevPoint = null;
while(!token.isEOF() && !token.isKeyword())
{
prevPoint = doPoint(kListType, prevPoint, list.getDimension());
}
// only stores list as bondRot if bondRot mode is on.
if (rotModeIsOn()) {
storeRotList(list);
}
}
//}}}
//{{{ doPoint
//##################################################################################################
/** Only called by doList() */
KPoint doPoint(String kListType, KPoint prevPoint, int dimension) throws IOException
{
KPoint point;
String defaultPointID;
if(prevPoint == null) defaultPointID = list.getName();
else defaultPointID = prevPoint.getName();
if(kListType.equals(KList.VECTOR)) point = new VectorPoint(list, defaultPointID, (VectorPoint)prevPoint);
else if(kListType.equals(KList.DOT)) point = new DotPoint(list, defaultPointID);
else if(kListType.equals(KList.MARK)) point = new MarkerPoint(list, defaultPointID);
else if(kListType.equals(KList.LABEL)) point = new LabelPoint(list, defaultPointID);
else if(kListType.equals(KList.TRIANGLE)) point = new TrianglePoint(list, defaultPointID, (TrianglePoint)prevPoint);
else if(kListType.equals(KList.RIBBON)) point = new TrianglePoint(list, defaultPointID, (TrianglePoint)prevPoint);
else if(kListType.equals(KList.RING)) point = new RingPoint(list, defaultPointID);
else if(kListType.equals(KList.BALL)) point = new BallPoint(list, defaultPointID);
else if(kListType.equals(KList.SPHERE)) point = new SpherePoint(list, defaultPointID);
else if(kListType.equals(KList.ARROW)) point = new ArrowPoint(list, defaultPointID, (VectorPoint)prevPoint);
else throw new IllegalArgumentException("Unrecognized list type '"+kListType+"'");
float[] allCoords = null;
if(dimension > 3)
{
allCoords = new float[dimension];
point.setAllCoords(allCoords);
}
boolean pointIdFound = false;
int coordsFound = 0;
while(!token.isEOF() && !token.isKeyword() && (!token.isIdentifier() || !pointIdFound) && coordsFound < dimension)
{
if(token.isIdentifier())
{
pointIdFound = true;
if(!token.getString().equals("\"")) point.setName(token.getString());
}
else if(token.isNumber())
{
float f = token.getFloat();
if(coordsFound == 0) point.setX(f);
else if(coordsFound == 1) point.setY(f);
else if(coordsFound == 2) point.setZ(f);
if(allCoords != null) allCoords[coordsFound] = f;
coordsFound++;
}
else if(token.isAspect()) point.setAspects(token.getString());
else if(token.isSingleQuote()) point.setPmMask(kinemage.toPmBitmask(token.getString(), true, true));
else if(token.isLiteral())
{
String s = token.getString();
if(s.equals("P") || s.equals("p") || s.equals("M") || s.equals("m"))
{
if(kListType.equals(KList.TRIANGLE) || kListType.equals(KList.RIBBON)) {} // see "X" flag, below
else point.setPrev(null);
}
else if(s.equals("X") || s.equals("x")) point.setPrev(null); // P doesn't work for triangle, ribbon
else if(s.equals("L") || s.equals("l") || s.equals("D") || s.equals("d")) {}
else if(s.equals("T") || s.equals("t")) {} // to avoid error messages for Mage ribbon/triangle lists
else if(s.equals("U") || s.equals("u")) point.setUnpickable(true);
else if(s.equals("ghost")) point.setGhost(true);
else if(s.startsWith("width"))
{
try { point.setWidth(Integer.parseInt(s.substring(5))); }
catch(NumberFormatException ex) {}
}
else if(kinemage.getAllPaintMap().containsKey(s)) point.setColor(kinemage.getPaintForName(s));
else error("Unrecognized literal '"+s+"' will be ignored");
}
else if(token.isProperty())
{
String s = token.getString();
token.advance(); // past key
if(s.equals("r="))
{
if(token.isNumber()) point.setRadius(token.getFloat());
else error("r= was not followed by a number");
}
else error("Unrecognized property '"+s+" "+token.getString()+"' will be ignored");
}
else if(token.isComment())
{
point.setComment(token.getString());
}
else error("Unrecognized token '"+token.getString()+"' will be ignored");
token.advance();
}
// Avoid creating bogus points from trailing junk, like empty comments.
if(pointIdFound || coordsFound > 0)
{
list.add(point);
return point;
}
else
{
error("Junk point will be ignored (no ID, no coordinates)");
return null; // point not added to list, so it's GC'd
}
}
//}}}
//{{{ do{Text, Caption, Title, Copyright, PdbFile, Command}
//##################################################################################################
void doText() throws IOException
{
atText.append(token.advanceToKeyword().trim()).append("\n\n");
}
void doCaption() throws IOException
{
checkKinemage();
atText.append("CAPTION for "+kinemage.getName()+":\n ");
atText.append(token.advanceToKeyword().trim()).append("\n\n");
}
void doTitle() throws IOException
{
checkKinemage();
token.advance();
if(token.isIdentifier()) { kinemage.setName(token.getString()); token.advance(); }
else error("@title was not followed by an identifier; found '"+token.getString()+"' instead");
}
void doCopyright() throws IOException
{
token.advance();
if(token.isIdentifier())
{
if(kinemage != null) atText.append("'"+kinemage.getName()+"' is ");
atText.append("COPYRIGHT (C) ").append(token.getString()).append("\n\n");
token.advance();
}
else error("@copyright was not followed by an identifier; found '"+token.getString()+"' instead");
}
void doPdbFile() throws IOException
{
checkKinemage();
token.advance();
if(token.isIdentifier()) { kinemage.atPdbfile = token.getString(); token.advance(); }
else error("@pdbfile was not followed by an identifier; found '"+token.getString()+"' instead");
}
void doCommand() throws IOException
{
checkKinemage();
token.advance();
if(token.isIdentifier()) { kinemage.atCommand = token.getString(); token.advance(); }
else error("@command was not followed by an identifier; found '"+token.getString()+"' instead");
}
//}}}
//{{{ getView, do{ViewID, Zoom, Span, Clip}
//##################################################################################################
KingView getView()
{
checkKinemage();
String s = token.getString();
StringBuffer keybuf = new StringBuffer();
int i;
for(char c = s.charAt(i = 1); Character.isDigit(c); c = s.charAt(++i))
{ keybuf.append(c); }
String key = keybuf.toString();
if(key.equals("")) key = "1";
KingView view = (KingView)viewMap.get(key);
if(view == null)
{
view = new KingView(kinemage);
kinemage.addView(view);
viewMap.put(key, view);
}
return view;
}
void doViewID() throws IOException
{
KingView view = getView();
token.advance();
if(token.isIdentifier()) { view.setName(token.getString()); token.advance(); }
else error("@viewid was not followed by an identifier; found '"+token.getString()+"' instead");
}
void doZoom() throws IOException
{
KingView view = getView();
token.advance();
if(token.isNumber()) { view.setZoom(token.getFloat()); token.advance(); }
else error("@zoom was not followed by a number; found '"+token.getString()+"' instead");
}
void doSpan() throws IOException
{
KingView view = getView();
token.advance();
if(token.isNumber()) { view.setSpan(token.getFloat()); token.advance(); }
else error("@span was not followed by a number; found '"+token.getString()+"' instead");
}
void doClip() throws IOException
{
KingView view = getView();
token.advance();
if(token.isNumber()) { view.setClip(token.getFloat() / 200f); token.advance(); }
else error("@zslab was not followed by a number; found '"+token.getString()+"' instead");
}
//}}}
//{{{ do{Center, Matrix, AxisChoice}
//##################################################################################################
void doCenter() throws IOException
{
KingView view = getView();
try
{
float cx, cy, cz;
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
cx = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
cy = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
cz = token.getFloat();
token.advance();
view.setCenter(cx, cy, cz);
}
catch(IllegalArgumentException ex)
{ error("@center was not followed by 3 numbers; found '"+token.getString()+"' instead"); }
}
void doAxisChoice() throws IOException
{
KingView view = getView();
try
{
int ix, iy, iz;
token.advance(); if(!token.isInteger()) throw new IllegalArgumentException();
ix = token.getInt();
token.advance(); if(!token.isInteger()) throw new IllegalArgumentException();
iy = token.getInt();
token.advance(); if(!token.isInteger()) throw new IllegalArgumentException();
iz = token.getInt();
token.advance();
view.setViewingAxes(new int[] {
Math.max(ix-1, 0),
Math.max(iy-1, 0),
Math.max(iz-1, 0)
});
}
catch(IllegalArgumentException ex)
{ error("@axischoice was not followed by 3 integers; found '"+token.getString()+"' instead"); }
}
void doMatrix() throws IOException
{
KingView view = getView();
try
{
// This KiNG-style (premultiplied) transformation matrix
// is the transpose of the Mage-style (postmultiplied) matrix.
float[][] km = new float[3][3];
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[0][0] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[1][0] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[2][0] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[0][1] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[1][1] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[2][1] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[0][2] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[1][2] = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
km[2][2] = token.getFloat();
token.advance();
view.setMatrix(km);
}
catch(IllegalArgumentException ex)
{ error("@matrix was not followed by 9 numbers; found '"+token.getString()+"' instead"); }
}
//}}}
//{{{ do{WhiteBackground, Onewidth, Thinline, Perspective, Flat, ListColorDominant, Lens}
//##################################################################################################
void doWhiteBackground() throws IOException
{
checkKinemage();
kinemage.atWhitebackground = true;
token.advance();
}
void doOnewidth() throws IOException
{
checkKinemage();
kinemage.atOnewidth = true;
token.advance();
}
void doThinline() throws IOException
{
checkKinemage();
kinemage.atThinline = true;
token.advance();
}
void doPerspective() throws IOException
{
checkKinemage();
kinemage.atPerspective = true;
token.advance();
}
void doFlat() throws IOException
{
checkKinemage();
kinemage.atFlat = true;
token.advance();
}
void doListColorDominant() throws IOException
{
checkKinemage();
kinemage.atListcolordominant = true;
token.advance();
}
void doLens() throws IOException
{
checkKinemage();
token.advance();
if(token.isNumber()) { kinemage.atLens = token.getDouble(); token.advance(); }
else error("@lens was not followed by a number; found '"+token.getString()+"' instead");
}
//}}}
//{{{ do{Colorset, HsvColor}
//##################################################################################################
void doColorset() throws IOException
{
checkKinemage();
Map pmap = kinemage.getAllPaintMap();
try
{
String cset, color;
token.advance(); if(!token.isIdentifier()) throw new IllegalArgumentException();
cset = token.getString();
token.advance(); if(!token.isLiteral()) throw new IllegalArgumentException();
color = token.getString();
if(!pmap.containsKey(color)) throw new IllegalArgumentException();
token.advance();
KPaint paint = KPaint.createAlias(cset, kinemage.getPaintForName(color));
kinemage.addPaint(paint);
}
catch(IllegalArgumentException ex)
{ error("@colorset was not followed by an identifier and a recognized color; found '"+token.getString()+"' instead"); }
}
void doHsvColor() throws IOException
{
checkKinemage();
try
{
String colorName;
float bHue, bSat, bVal, wHue, wSat, wVal;
token.advance(); if(!token.isIdentifier()) throw new IllegalArgumentException();
colorName = token.getString();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
bHue = wHue = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
bSat = wSat = token.getFloat();
token.advance(); if(!token.isNumber()) throw new IllegalArgumentException();
bVal = wVal = token.getFloat();
token.advance(); if(token.isNumber())
{
wHue = token.getFloat();
token.advance(); if(token.isNumber())
{
wSat = token.getFloat();
token.advance(); if(token.isNumber())
{
wVal = token.getFloat();
token.advance();
}
}
}
KPaint paint = KPaint.createLightweightHSV(colorName, bHue, bSat, bVal, wHue, wSat, wVal);
kinemage.addPaint(paint);
}
catch(IllegalArgumentException ex)
{ error("@hsvcolor was not followed by an identifier and 3 - 6 numbers; found '"+token.getString()+"' instead"); }
}
//}}}
//{{{ do{Master, Pointmaster}
//##################################################################################################
// This just creates the master button ahead of time,
// so it will appear in the specified order later on.
void doMaster() throws IOException
{
checkKinemage();
token.advance();
if(token.isIdentifier())
{
MasterGroup master = kinemage.getMasterByName(token.getString());
token.advance();
while(!token.isEOF() && !token.isKeyword())
{
if(token.isLiteral())
{
if(token.getString().equals("indent")) master.indent = true;
else if(token.getString().equals("on")) master.setOnForced(true); // will turn on ALL target groups during sync
else if(token.getString().equals("off")) master.setOnForced(false); // will turn off ALL target groups during sync
else error("Unrecognized literal '"+token.getString()+"' will be ignored");
}
else error("Unrecognized token '"+token.getString()+"' will be ignored");
token.advance();
}
}
else error("@master was not followed by an identifier; found '"+token.getString()+"' instead");
}
// This both creates the master and sets its pointmaster bitflags
// Syntax:
// @pointmaster 'x' {Button name} [indent]
// Possible to do the following (but why?):
// @pointmaster 'abc' {Multi-master} [indent]
void doPointmaster() throws IOException
{
checkKinemage();
try
{
String charFlags, masterName;
token.advance(); if(!token.isSingleQuote()) throw new IllegalArgumentException();
charFlags = token.getString();
token.advance(); if(!token.isIdentifier()) throw new IllegalArgumentException();
masterName = token.getString();
token.advance();
MasterGroup master = kinemage.getMasterByName(masterName);
master.setPmMask(charFlags);
while(!token.isEOF() && !token.isKeyword())
{
if(token.isLiteral())
{
if(token.getString().equals("indent")) master.indent = true;
else if(token.getString().equals("on")) master.setOnForced(true); // will turn on ALL target pts during sync (no effect)
else if(token.getString().equals("off")) master.setOnForced(false); // will turn off ALL target pts during sync
else error("Unrecognized literal '"+token.getString()+"' will be ignored");
}
else error("Unrecognized token '"+token.getString()+"' will be ignored");
token.advance();
}
}
catch(IllegalArgumentException ex)
{ error("@pointmaster was not followed by a single-quoted string and an identifier; found '"+token.getString()+"' instead"); }
}
//}}}
//{{{ doAspect
//##################################################################################################
void doAspect() throws IOException
{
checkKinemage();
String s = token.getString();
StringBuffer keybuf = new StringBuffer();
int i;
for(char c = s.charAt(i = 1); Character.isDigit(c); c = s.charAt(++i))
{ keybuf.append(c); }
String key = keybuf.toString();
if(key.equals("")) key = "1";
try
{
int index = Integer.parseInt(key);
token.advance(); if(!token.isIdentifier()) throw new IllegalArgumentException();
kinemage.createAspect(token.getString(), new Integer(index));
token.advance();
}
catch(NumberFormatException ex)
{ error("@aspect was not recognized; '"+key+"' is not an integer"); }
catch(IllegalArgumentException ex)
{ error("@aspect was not followed by an identifier; found '"+token.getString()+"' instead"); }
}
//}}}
//{{{ doDimensions, doDimMinMax
//##################################################################################################
void doDimensions() throws IOException
{
checkKinemage();
token.advance();
if(token.isIdentifier()) while(token.isIdentifier())
{
kinemage.dimensionNames.add(token.getString());
token.advance();
}
else error("@dimensions was not followed by 1+ identifiers; found '"+token.getString()+"' instead");
}
void doDimMinMax() throws IOException
{
checkKinemage();
token.advance();
if(token.isNumber()) while(token.isNumber())
{
kinemage.dimensionMinMax.add(new Double(token.getDouble()));
token.advance();
}
else error("@dimminmax was not followed by 1+ numbers; found '"+token.getString()+"' instead");
}
//}}}
//{{{ storeBondRot, storeRotList
//##################################################################################################
/**
* Private functions used to store bondrots. Numbered BondRots work by creating a new bond rot
* everytime a #bondrot is encountered in the kinemage. A bondrot is closed whenever a new #bondrot
* is encountered with a # less than or equal to the bondrot.
**/
private void storeBondRot(int bondNum, String nm, double angle) {
Integer bondInt = new Integer(bondNum);
Map higherRots = new TreeMap();
if (bondNum != -1) {
higherRots = bondRots.tailMap(bondInt);
}
if (!(higherRots.isEmpty())) {
Collection closingRots = higherRots.values();
Iterator iter = closingRots.iterator();
while (iter.hasNext()) {
BondRot toBeClosed = (BondRot) iter.next();
toBeClosed.setOpen(false);
closedBondRots.add(toBeClosed);
//System.out.println("Bond rots less than or equal to " + bondInt + " closed");
}
}
if (bondNum != -1) {
bondRots = new TreeMap(bondRots.headMap(bondInt)); //to clear map of all bondrots with higher numbers
}
BondRot newRot = new BondRot(bondNum, nm, angle);
bondRots.put(bondInt, newRot);
}
// for putting a klist into all currently open bondrots.
private void storeRotList(KList list) {
Collection bondRotColl = bondRots.values();
Iterator iter = bondRotColl.iterator();
while (iter.hasNext()) {
BondRot rot = (BondRot) iter.next();
if (rot.isOpen()) {
rot.add(list);
}
}
}
//}}}
//{{{ closeBondRots, rotModeIsOn
//##################################################################################################
private ArrayList closeBondRots() {
//need to close all open bondrots
if (bondRots != null) {
Collection closingRots = bondRots.values();
Iterator closeIter = closingRots.iterator();
while (closeIter.hasNext()) {
BondRot toBeClosed = (BondRot) closeIter.next();
toBeClosed.setOpen(false);
closedBondRots.add(toBeClosed);
}
bondRots = null;
}
return closedBondRots;
}
/**
* Returns whether bondRots have been encountered in the kinemage.
**/
public boolean rotModeIsOn() {
return !(bondRots.isEmpty());
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ Main() and main()
//##################################################################################################
/**
* Main() function for running as an application.
* Takes a kinemage on stdin and writes tokens to stdout
*/
public void Main()
{
System.out.println("Read "+kinemages.size()+" kinemages:");
for(Iterator ki = kinemages.iterator(); ki.hasNext(); )
{
kinemage = (Kinemage)ki.next();
System.out.println(" Kinemage: "+kinemage.getName()+" ("+kinemage.children.size()+" groups)");
for(Iterator gi = kinemage.iterator(); gi.hasNext(); )
{
group = (KGroup)gi.next();
System.out.println(" Group: "+group.getName()+" ("+group.children.size()+" subgroups)");
for(Iterator si = group.iterator(); si.hasNext(); )
{
subgroup = (KSubgroup)si.next();
System.out.println(" Subgroup: "+subgroup.getName()+" ("+subgroup.children.size()+" lists)");
for(Iterator li = subgroup.iterator(); li.hasNext(); )
{
list = (KList)li.next();
System.out.println(" List: "+list.getName()+" ("+list.children.size()+" points)");
}
}
}
}
System.out.println();
System.out.println();
}
public static void main(String[] args)
{
try
{
Reader input = new InputStreamReader(System.in);
if(args.length > 0)
{
System.err.println("*** Takes a kinemage on stdin or as first arg and writes structure to stdout.");
input = new FileReader(args[0]);
}
long time = System.currentTimeMillis();
KinfileParser parser = new KinfileParser();
parser.parse(new LineNumberReader(input));
time = System.currentTimeMillis() - time;
System.out.println("END OF FILE ("+time+" ms)");
System.gc();
System.out.println("Using "+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())+" bytes");
parser.Main();
}
catch(Throwable t)
{ t.printStackTrace(SoftLog.err); }
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/StandardPainter.java 0000644 0000000 0000000 00000033600 11531212670 021626 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* StandardPainter
paints kinemage graphics using standard calls
* on a java.awt.Graphics object. Must be initialized with setGraphics()
* before use!
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Fri May 21 19:11:16 EDT 2004
*/
public class StandardPainter implements Painter
{
//{{{ Constants
/*
* Useful for benchmarking. Setting to false keeps us from drawing to screen.
* This should optimize away at compile time, like #ifdef in C.
*
* On my G4 PowerBook, transforming and all the paint calcs account for
* only about 10% of the total time required to render one frame.
*/
protected static final boolean REALLY_PAINT = true;
//}}}
//{{{ Variable definitions
//##############################################################################
boolean forceAA;
Graphics2D g = null;
Font font = null;
FontMetrics metrics = null;
Rectangle clipRgn = new Rectangle(0,0,1,1);
int[] xPoints = new int[6];
int[] yPoints = new int[6];
//}}}
//{{{ Constructor(s)
//##############################################################################
public StandardPainter(boolean forceAntialiasing)
{
super();
this.forceAA = forceAntialiasing;
}
//}}}
//{{{ paintBall
//##################################################################################################
public void paintBall(Paint paint, double x, double y, double z, double r, boolean showHighlight)
{
int d = (int)(2.0*r + 0.5);
if(d < 2) d = 2; // make sure balls don't disappear
// one disk
g.setPaint(paint);
if(REALLY_PAINT) g.fillOval((int)(x-r), (int)(y-r), d, d);
// Black rim, causes ~10% speed penalty but useful for visualization!
try
{
Color c = (Color) paint;
if(d >= 10 && c.getAlpha() == 255)
{
g.setPaint(KPaint.black); // wants to merge with the background
if(REALLY_PAINT) g.drawOval((int)(x-r), (int)(y-r), d, d);
}
}
catch(ClassCastException ex)
{
ex.printStackTrace();
System.err.println("StandardPainter: tried painting with non-Color type of Paint");
}
// highlight
if(showHighlight)
{
double off = 0.5 * r;
d = (int)(0.3*r)+1;
g.setPaint(Color.white); // wants to be bright white no matter what
if(REALLY_PAINT) g.fillOval((int)(x-off), (int)(y-off), d, d);
}
}
//}}}
//{{{ paintDot
//##################################################################################################
public void paintDot(Paint paint, double x, double y, double z, int width)
{
int off = width/2;
g.setPaint(paint);
if(REALLY_PAINT) g.fillRect((int)(x-off), (int)(y-off), width, width);
}
//}}}
//{{{ paintLabel
//##################################################################################################
public void paintLabel(Paint paint, String label, double x, double y, double z)
{
g.setPaint(paint);
g.setFont(font);
if(REALLY_PAINT) g.drawString(label, (int)x, (int)y);
}
//}}}
//{{{ paintMarker
//##################################################################################################
public void paintMarker(Paint paint, double x, double y, double z, int width, int paintStyle)
{
int cx = (int)x, cy = (int)y;
int one = width, two = 2*width, three = 3*width, four = 4*width, five = 5*width,
six = 6*width, seven = 7*width, ten = 10*width, eleven = 11*width;
g.setPaint(paint);
if(REALLY_PAINT)
{
// Large discs and boxes
if((paintStyle & MarkerPoint.BOX_L) != 0) g.fillRect(cx-five, cy-five, eleven, eleven);
else if((paintStyle & MarkerPoint.DISC_L) != 0) g.fillOval(cx-five, cy-five, eleven, eleven);
// Medium discs and boxes
if((paintStyle & MarkerPoint.BOX_M) != 0) g.fillRect(cx-three, cy-three, seven, seven);
else if((paintStyle & MarkerPoint.DISC_M) != 0) g.fillOval(cx-three, cy-three, seven, seven);
// Small discs and boxes
if((paintStyle & MarkerPoint.BOX_S) != 0) g.fillRect(cx-one, cy-one, three, three);
else if((paintStyle & MarkerPoint.DISC_S) != 0) g.fillOval(cx-one, cy-one, three, three);
// Crosses
if((paintStyle & MarkerPoint.CROSS_S) != 0) { g.drawLine(cx, cy-one, cx, cy+one); g.drawLine(cx-one, cy, cx+one, cy); }
if((paintStyle & MarkerPoint.CROSS_M) != 0) { g.drawLine(cx, cy-three, cx, cy+three); g.drawLine(cx-three, cy, cx+three, cy); }
if((paintStyle & MarkerPoint.CROSS_L) != 0) { g.drawLine(cx, cy-five, cx, cy+five); g.drawLine(cx-five, cy, cx+five, cy); }
if((paintStyle & MarkerPoint.CROSS_2) != 0)
{
g.drawLine(cx-one, cy-five, cx-one, cy+five); g.drawLine(cx+one, cy-five, cx+one, cy+five);
g.drawLine(cx-five, cy-one, cx+five, cy-one); g.drawLine(cx-five, cy+one, cx+five, cy+one);
}
// X's
if((paintStyle & MarkerPoint.X_S) != 0) { g.drawLine(cx-one, cy-one, cx+one, cy+one); g.drawLine(cx-one, cy+one, cx+one, cy-one); }
if((paintStyle & MarkerPoint.X_M) != 0) { g.drawLine(cx-three, cy-three, cx+three, cy+three); g.drawLine(cx-three, cy+three, cx+three, cy-three); }
if((paintStyle & MarkerPoint.X_L) != 0) { g.drawLine(cx-five, cy-five, cx+five, cy+five); g.drawLine(cx-five, cy+five, cx+five, cy-five); }
if((paintStyle & MarkerPoint.X_2) != 0)
{
g.drawLine(cx-four, cy-five, cx+five, cy+four); g.drawLine(cx-five, cy-four, cx+four, cy+five);
g.drawLine(cx-four, cy+five, cx+five, cy-four); g.drawLine(cx-five, cy+four, cx+four, cy-five);
}
// Squares
if((paintStyle & MarkerPoint.SQUARE_S) != 0) g.drawRect(cx-one, cy-one, two, two);
if((paintStyle & MarkerPoint.SQUARE_M) != 0) g.drawRect(cx-three, cy-three, six, six);
if((paintStyle & MarkerPoint.SQUARE_L) != 0) g.drawRect(cx-five, cy-five, ten, ten);
// Circles
if((paintStyle & MarkerPoint.RING_S) != 0) g.drawOval(cx-one, cy-one, two, two);
if((paintStyle & MarkerPoint.RING_M) != 0) g.drawOval(cx-three, cy-three, six, six);
if((paintStyle & MarkerPoint.RING_L) != 0) g.drawOval(cx-five, cy-five, ten, ten);
}
}
//}}}
//{{{ paintSphereDisk
//##################################################################################################
public void paintSphereDisk(Paint paint, double x, double y, double z, double r)
{
int d = (int)(2.0*r + 0.5);
if(d < 2) d = 2; // make sure balls don't disappear
// one disk
g.setPaint(paint);
if(REALLY_PAINT) g.fillOval((int)(x-r), (int)(y-r), d, d);
}
//}}}
//{{{ paintTriangle
//##################################################################################################
public void paintTriangle(Paint paint,
double x1, double y1, double z1,
double x2, double y2, double z2,
double x3, double y3, double z3)
{
g.setPaint(paint);
xPoints[0] = (int)x1; yPoints[0] = (int)y1;
xPoints[1] = (int)x2; yPoints[1] = (int)y2;
xPoints[2] = (int)x3; yPoints[2] = (int)y3;
if(REALLY_PAINT) g.fillPolygon(xPoints, yPoints, 3);
}
//}}}
//{{{ paintVector
//##################################################################################################
public void paintVector(Paint paint, int width, int widthCue,
double x1, double y1, double z1,
double x2, double y2, double z2)
{
g.setPaint(paint);
if(REALLY_PAINT) prettyLine((int)x1, (int)y1, (int)x2, (int)y2, KPalette.lineWidths[width-1][widthCue]);
}
//}}}
//{{{ prettyLine
//##################################################################################################
/** Draws a thick line with nice ends, using fillPolygon(). Slightly slower (30-35%) than fastLine(). */
void prettyLine(int x1, int y1, int x2, int y2, int width)
{
int s, e, abs_x2_x1, abs_y2_y1;
s = -width / 2; // Start offset
e = s + width; // End offset
abs_x2_x1 = Math.abs(x2 - x1);
abs_y2_y1 = Math.abs(y2 - y1);
// horizontal --
if( abs_x2_x1 > abs_y2_y1 )
{
// left to right
if( x1 < x2 )
{
xPoints[0] = x1 ; xPoints[1] = x1+s; xPoints[2] = x1; xPoints[3] = x2; xPoints[4] = x2-s; xPoints[5] = x2;
yPoints[0] = y1+s; yPoints[1] = y1; yPoints[2] = y1+e; yPoints[3] = y2+e; yPoints[4] = y2; yPoints[5] = y2+s;
}
// right to left
else
{
xPoints[0] = x1 ; xPoints[1] = x1-s; xPoints[2] = x1; xPoints[3] = x2; xPoints[4] = x2+s; xPoints[5] = x2;
yPoints[0] = y1+s; yPoints[1] = y1; yPoints[2] = y1+e; yPoints[3] = y2+e; yPoints[4] = y2; yPoints[5] = y2+s;
}
}
// vertical |
else
{
// top to bottom
if( y1 < y2 )
{
xPoints[0] = x1+s; xPoints[1] = x1; xPoints[2] = x1+e; xPoints[3] = x2+e; xPoints[4] = x2; xPoints[5] = x2+s;
yPoints[0] = y1 ; yPoints[1] = y1+s; yPoints[2] = y1; yPoints[3] = y2; yPoints[4] = y2-s; yPoints[5] = y2;
}
// bottom to top
else
{
xPoints[0] = x1+s; xPoints[1] = x1; xPoints[2] = x1+e; xPoints[3] = x2+e; xPoints[4] = x2; xPoints[5] = x2+s;
yPoints[0] = y1 ; yPoints[1] = y1-s; yPoints[2] = y1; yPoints[3] = y2; yPoints[4] = y2+s; yPoints[5] = y2;
}
}
g.fillPolygon(xPoints, yPoints, 6);
}
//}}}
//{{{ fastLine
//##################################################################################################
/** Draws a thick line using multiple calls to drawLine(). Not as robust as prettyLine(), but slightly faster. */
void fastLine(int x1, int y1, int x2, int y2, int width)
{
g.drawLine(x1, y1, x2, y2);
// Then, draw more lines until we get to the approximate thickness.
// This idea is borrowed from JavaMage, and possibly regular Mage, too.
// The plan is to step along x if it's a mostly vertical line, along y if it's mostly horizontal
int start, end, i;
start = -width/2;
end = start + width;
// step along y
if( Math.abs(x2-x1) > Math.abs(y2-y1) )
{
for(i = start; i < 0; i++) g.drawLine(x1, y1+i, x2, y2+i);
for(i = 1; i < end; i++) g.drawLine(x1, y1+i, x2, y2+i);
}
// step along x
else
{
for(i = start; i < 0; i++) g.drawLine(x1+i, y1, x2+i, y2);
for(i = 1; i < end; i++) g.drawLine(x1+i, y1, x2+i, y2);
}
}
//}}}
//{{{ drawOval
//##################################################################################################
public void drawOval(Paint paint, double x, double y, double z, double width, double height)
{
// one disk
g.setPaint(paint);
if(REALLY_PAINT) g.drawOval((int)(x - width/2), (int)(y - height/2), (int)width, (int)height);
}
public void drawOval(Paint paint, int linewidth, int widthCue, double x, double y, double z, double width, double height)
{
g.setPaint(paint);
int startx = (int)(x - width/2.0 - linewidth/2.0);
int starty = (int)(y - height/2.0 - linewidth/2.0);
int diamx = (int)( width + linewidth);
int diamy = (int)(height + linewidth);
if(REALLY_PAINT)
{
for(int i = 0; i < linewidth; i++)
{
g.drawOval(startx, starty, diamx, diamy);
startx += 1;
starty += 1;
diamx -= 2;
diamy -= 2;
}
}
}
//}}}
//{{{ setGraphics, setFont, getLabelWidth/Ascent/Descent
//##############################################################################
/** Sets the Graphics object this painter will use for painting. */
public void setGraphics(Graphics2D g2)
{
this.g = g2;
if(forceAA)
this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if(font != null)
this.metrics = g.getFontMetrics(font);
}
public void setFont(Font f)
{
this.font = f;
if(g != null)
this.metrics = g.getFontMetrics(f);
}
public int getLabelWidth(String s)
{ return metrics.stringWidth(s); }
public int getLabelAscent(String s)
{ return metrics.getAscent(); }
public int getLabelDescent(String s)
{ return metrics.getDescent(); }
//}}}
//{{{ setViewport, clearCanvas
//##############################################################################
public void setViewport(int x, int y, int width, int height)
{
clipRgn.setBounds(x, y, width, height);
g.setClip(clipRgn);
}
public void clearCanvas(Color color)
{
g.setColor(color);
if(REALLY_PAINT) g.fillRect(clipRgn.x, clipRgn.y, clipRgn.width, clipRgn.height);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KinfileTokenizer.java 0000644 0000000 0000000 00000043521 11531212670 022022 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.util.SoftLog;
//}}}
/**
* KinfileTokenizer
is a second-generation implementation
* of a tokenizer that complies with the Kinemage File Format, v1.0.
*
* It takes in a stream of characters and outputs discrete tokens,
* stripped of whitespace and quoting characters.
* [Equals signs (=) and at signs (@) are preserved.]
*
* It currently does not check for the presence of illegal characters.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Mon Apr 7 13:34:38 EDT 2003
*/
public class KinfileTokenizer //extends ... implements ...
{
//{{{ Constants
static final String TYPE_NONE = "nil-type";
static final String TYPE_IDENTIFIER = "identifier";
static final String TYPE_COMMENT = "comment";
static final String TYPE_ASPECT = "aspect";
static final String TYPE_SINGLE_QUOTE = "s-quote";
static final String TYPE_DOUBLE_QUOTE = "d-quote";
static final String TYPE_KEYWORD = "keyword";
static final String TYPE_PROPERTY = "property";
static final String TYPE_INTEGER = "integer";
static final String TYPE_NUMBER = "number";
static final String TYPE_LITERAL = "literal";
static final int NIL_CHARACTER = -1;
//}}}
//{{{ Variable definitions
//##################################################################################################
LineNumberReader in;
char[] buffer = new char[256];
int bufferIndex = 0;
int firstChar; // first char of next token
long charsRead; // a count of how many characters we've read
String stringValue;
double doubleValue;
String type;
boolean isBOL;
boolean isEOF;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a new KinfileTokenizer on the given input stream,
* and advances it to the first token.
* @throws IOException if there's a problem reading from the input stream
*/
public KinfileTokenizer(LineNumberReader input) throws IOException
{
in = input;
charsRead = 0;
isEOF = false;
// A trick -- this makes the tokenizer think that
// the first token is at the beginning of a line.
firstChar = '\n';
advance();
}
//}}}
//{{{ buffer{Append, ToString, Clear}
//##################################################################################################
/**
* We use our own custom buffer system because
* StringBuffers allocate memory 16 chars (32 bytes)
* at a time, which is then wasted when we convert
* them to Strings.
*/
void bufferAppend(char ch)
{
if(bufferIndex >= buffer.length)
{
char[] newBuffer = new char[buffer.length * 2];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
error("Token too long; increased buffer size to "+buffer.length);
}
buffer[bufferIndex++] = ch;
}
/** Returns the current buffer contents as a string */
String bufferToString()
{ return new String(buffer, 0, bufferIndex); }
/** Empties the buffer contents */
void bufferClear()
{ bufferIndex = 0; }
//}}}
//{{{ in_read, getCharsRead, error
//##################################################################################################
/**
* A replacement for in.read() that allows us to track the
* total number of character read so far.
* Causes a performance penalty of less than 1%.
*/
int in_read() throws IOException
{
charsRead++;
return in.read();
}
/** Returns the number of characters read in thus far */
public long getCharsRead()
{
return charsRead;
}
void error(String msg)
{
SoftLog.err.println("[line "+(in.getLineNumber()+1)+"] "+msg);
}
//}}}
//{{{ advance
//##################################################################################################
/**
* Advances this tokenizer to the next token in the stream.
* The type of token can be queried with the isXXX() functions,
* and the value (in the appropriate form) can be retrieved with the getXXX() functions.
* @throws IOException if there's a problem reading from the input stream
*/
public void advance() throws IOException
{
int c;
// Init variables
stringValue = null;
doubleValue = Double.NaN;
type = TYPE_NONE;
isBOL = false;
bufferClear();
// Get first character (from stream or previously read)
if(firstChar > 0) c = firstChar;
else c = in_read();
firstChar = NIL_CHARACTER;
// Skip leading whitespace
while(c == ' ' || c == '\n' || c == ',' || c == '\t' || c == '\f')
{
// LNR translates all linefeeds into '\n'
isBOL = (c == '\n');
c = in_read();
}
// Guess token type based on first character
if(c == -1)
{
isEOF = true;
return;
}
else if(c == '{')
{
readQuoted('{', '}');
type = TYPE_IDENTIFIER;
}
else if(c == '<')
{
readQuoted('<', '>');
type = TYPE_COMMENT;
}
else if(c == '(')
{
readQuoted('(', ')');
type = TYPE_ASPECT;
}
else if(c == '\'')
{
readQuoted('\'');
type = TYPE_SINGLE_QUOTE;
}
else if(c == '"')
{
readQuoted('"');
type = TYPE_DOUBLE_QUOTE;
}
else
{
bufferAppend((char)c);
readUnquoted();
// type is set in readUnquoted()
}
bufferClear();
}
//}}}
//{{{ advanceToKeyword
//##################################################################################################
/**
* Reads ahead until encountering a keyword token,
* one that begins with an at sign (@) at the beginning of a line.
* All the characters from the current position to the
* start of the keyword are returned by this function.
* @throws IOException if there's a problem reading from the input stream
*/
public String advanceToKeyword() throws IOException
{
int c;
// Init variables
stringValue = null;
doubleValue = Double.NaN;
type = TYPE_NONE;
isBOL = false;
bufferClear();
// Get first character (from stream or previously read)
if(firstChar > 0) c = firstChar;
else c = in_read();
firstChar = NIL_CHARACTER;
// Read until we find a keyword
StringBuffer longBuf = new StringBuffer(1024);
while(!(isBOL && c == '@'))
{
longBuf.append((char)c);
// LNR translates all linefeeds into '\n'
isBOL = (c == '\n');
c = in_read();
if(c == -1)
{
isEOF = true;
return longBuf.toString();
}
}
String retVal = longBuf.toString();
bufferAppend((char)c);
readUnquoted();
bufferClear();
return retVal;
}
//}}}
//{{{ readQuoted
//##################################################################################################
/** Sets stringValue and doubleValue; appends characters to buffer */
void readQuoted(char open, char close) throws IOException
{
int c, depth = 1;
while(depth > 0)
{
c = in_read();
if(c == -1) { depth = 0; error("Quoted token terminated by EOF; type = "+open+""+close); }
else if(c == open) { ++depth; bufferAppend((char)c); }
else if(c == close) { if(--depth > 0) bufferAppend((char)c); }
else bufferAppend((char)c);
}
stringValue = bufferToString();
doubleValue = Double.NaN;
}
/** Sets stringValue and doubleValue; appends characters to buffer */
void readQuoted(char close) throws IOException
{
int c, depth = 1;
while(depth > 0)
{
c = in_read();
if(c == -1) { depth = 0; error("Quoted token terminated by EOF; type = "+close+""+close); }
else if(c == close) depth--;
else bufferAppend((char)c);
}
stringValue = bufferToString();
doubleValue = Double.NaN;
}
//}}}
//{{{ readUnquoted
//##################################################################################################
/** Sets stringValue, doubleValue, and type; appends characters to buffer */
void readUnquoted() throws IOException
{
int c;
while(true)
{
c = in_read();
if(c == -1 || c == ' ' || c == '\n' || c == ',' || c == '\t' || c == '\f'
|| c == '{' || c == '<' || c == '(' || c == '\'' || c == '"')
{ firstChar = c; break; }
else if(c == '=')
{ bufferAppend((char)c); break; }
else bufferAppend((char)c);
}
/* This block allows spaces (but not newlines) to come between the word and the equals sign */
while(c == ' ' || c == ',' || c == '\t')
{
c = in_read();
if(c == '=')
{
bufferAppend('=');
firstChar = NIL_CHARACTER;
}
else firstChar = c;
}
/* This block allows spaces (but not newlines) to come between the word and the equals sign */
stringValue = bufferToString();
doubleValue = Double.NaN;
c = stringValue.charAt(0);
if(stringValue.startsWith("@") && isBOL()) type = TYPE_KEYWORD;
else if(stringValue.endsWith("=")) type = TYPE_PROPERTY;
else if(('0' <= c && c <= '9') || c == '.' || c == '-' || c == '+')
{
try {
doubleValue = Double.parseDouble(stringValue);
if(doubleValue == Math.rint(doubleValue)) type = TYPE_INTEGER;
else type = TYPE_NUMBER;
} catch(NumberFormatException ex) { type = TYPE_LITERAL; }
}
else type = TYPE_LITERAL;
}
//}}}
//{{{ is{BOL, EOF, etc}, getType
//##################################################################################################
/** Returns true if the current token occured at the Beginning Of a Line */
public boolean isBOL()
{ return isBOL; }
/** Returns true if we've reached the End Of File */
public boolean isEOF()
{ return isEOF; }
/** Returns true if the current token is an identifier */
public boolean isIdentifier()
{ return (type == TYPE_IDENTIFIER); }
/** Returns true if the current token is a comment */
public boolean isComment()
{ return (type == TYPE_COMMENT); }
/** Returns true if the current token is an aspect */
public boolean isAspect()
{ return (type == TYPE_ASPECT); }
/** Returns true if the current token is single quoted */
public boolean isSingleQuote()
{ return (type == TYPE_SINGLE_QUOTE); }
/** Returns true if the current token is double quoted */
public boolean isDoubleQuote()
{ return (type == TYPE_DOUBLE_QUOTE); }
/** Returns true if the current token is a keyword */
public boolean isKeyword()
{ return (type == TYPE_KEYWORD); }
/** Returns true if the current token is a property */
public boolean isProperty()
{ return (type == TYPE_PROPERTY); }
/** Returns true if the current token is an integer */
public boolean isInteger()
{ return (type == TYPE_INTEGER); }
/** Returns true if the current token is some kind of number */
public boolean isNumber()
{ return (type == TYPE_NUMBER || type == TYPE_INTEGER); }
/** Returns true if the current token is a string literal */
public boolean isLiteral()
{ return (type == TYPE_LITERAL); }
/** Returns the type of the current token as a string */
public String getType()
{ return type; }
//}}}
//{{{ get{String, Int, Float, Double}
//##################################################################################################
/**
* Returns the value of the current token as a string,
* or null if there is no token available.
*/
public String getString()
{
//if(stringValue == null)
// throw new IllegalStateException("No token is available");
return stringValue;
}
/**
* Returns the value of the current token as an integer.
* @throws IllegalStateException if the token is not an integer
*/
public int getInt()
{
if(!isInteger() || Double.isNaN(doubleValue) || doubleValue != Math.rint(doubleValue))
throw new IllegalStateException("[line "+(in.getLineNumber()+1)+"] Token is not an integer");
return (int)doubleValue;
}
/**
* Returns the value of the current token as a float.
* @throws IllegalStateException if the token is not a number
*/
public float getFloat()
{
if(!isNumber() || Double.isNaN(doubleValue))
throw new IllegalStateException("[line "+(in.getLineNumber()+1)+"] Token is not a number");
return (float)doubleValue;
}
/**
* Returns the value of the current token as a double.
* @throws IllegalStateException if the token is not a number
*/
public double getDouble()
{
if(!isNumber() || Double.isNaN(doubleValue))
throw new IllegalStateException("[line "+(in.getLineNumber()+1)+"] Token is not a number");
return doubleValue;
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ Main() and main()
//##################################################################################################
/**
* Main() function for running as an application.
* Takes a kinemage on stdin and writes tokens to stdout
*/
public void Main(boolean doCSS) throws IOException
{
if(doCSS)
{
System.out.println("
");
while(!isEOF())
{
String start, end, s = getString();
if(isBOL()) System.out.print("\n
");
if(isIdentifier()) { start = "{"; end = "}"; }
else if(isComment()) { start = "<"; end = ">"; }
else if(isAspect()) { start = "("; end = ")"; }
else if(isSingleQuote()) { start = "'"; end = "'"; }
else if(isDoubleQuote()) { start = "\""; end = "\""; }
else { start = ""; end = ""; }
System.out.print("
"+start+s+end+" ");
if(isKeyword() && (s.equals("@text") || s.equals("@caption")))
{
System.out.print("\n
");
System.out.print(advanceToKeyword());
System.out.print("
\n");
}
else advance();
}
System.out.println("\n
");
}
else
{
String s;
long time = System.currentTimeMillis();
while(!isEOF())
{
s = getString();
if(isKeyword() && (s.equals("@text") || s.equals("@caption")))
{
System.out.println("[>>> "+s+"]");
System.out.println(advanceToKeyword());
System.out.println("[<<< "+s+"]");
}
else
{
if(isBOL()) System.out.println("[BOL:"+justifyLeft(getType(), 10)+"] "+s);
else System.out.println("[ "+justifyLeft(getType(), 10)+"] "+s);
advance();
}
}
time = System.currentTimeMillis() - time;
System.out.println("END OF FILE ("+time+" ms)");
System.out.println();
System.out.println();
}
}
public static void main(String[] args)
{
boolean doCSS = false;
for(int i = 0; i < args.length; i++)
{
if("-css".equals(args[i])) doCSS = true;
else System.err.println("*** Takes a kinemage on stdin and writes tokens to stdout.");
}
try
{ new KinfileTokenizer(new LineNumberReader(new InputStreamReader(System.in))).Main(doCSS); }
catch(IOException ex)
{ ex.printStackTrace(SoftLog.err); }
}
//}}}
//{{{ justifyLeft
//##################################################################################################
/**
* Pads a string with spaces and left-justifies it.
*
* @param s the string to justify
* @param len the desired length
*/
public static String justifyLeft(String s, int len)
{
StringBuffer sb = new StringBuffer(s);
sb.ensureCapacity(len);
for(int i = s.length(); i < len; i++) sb.append(' ');
return sb.toString();
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/TransformSignalSubscriber.java 0000644 0000000 0000000 00000002532 11531212670 023700 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* TransformSignalSubscriber
allows objects to
* receive signals from a TransformSignal.
*
* Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Thu Mar 27 10:32:24 EST 2003
*/
public interface TransformSignalSubscriber //extends ... implements ...
{
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform);
}//class
king-2.21.120420/king/1.x_src/king/core/KinemageSignal.java 0000644 0000000 0000000 00000010256 11531212670 021423 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* KinemageSignal
provides a reusable framework
* for publish-subscribe message passing.
* This signal is used to notify listeners of changes to a kinemage.
*
* This signal is not thread-safe.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Thu Mar 27 10:11:30 EST 2003
*/
public class KinemageSignal implements KinemageSignalSubscriber
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
ArrayList subscribers;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public KinemageSignal()
{
subscribers = new ArrayList();
}
//}}}
//{{{ signalKinemage
//##################################################################################################
/**
* A call to this method will publish this signal (i.e., call this method)
* for each subscriber, one at a time, in the current thread.
* Because this class also implements the subscriber interface,
* these signals can be chained together to create deep networks.
*
* @param kinemage the Kinemage object that has changed
* @param bitmask a set of flags describing which properties have changed.
*/
public void signalKinemage(Kinemage kinemage, int bitmask)
{
KinemageSignalSubscriber subscriber;
Iterator iter = subscribers.iterator();
while(iter.hasNext())
{
subscriber = (KinemageSignalSubscriber)iter.next();
subscriber.signalKinemage(kinemage, bitmask);
}
}
//}}}
//{{{ subscribe, getSubscribers
//##################################################################################################
/**
* Adds a subscriber to this signal. The subscriber will be notified
* whenever this signal is activated. Every subscriber must be unique,
* so if there is some current subscriber oldSubscriber such that
* newSubscriber.equals(oldSubscriber)
, then oldSubscriber
* will be removed before newSubscriber is added.
*
*
Subscribers are notified in the same order they were added; however,
* they should NOT rely on this as it may change in future implementations.
*/
public void subscribe(KinemageSignalSubscriber newSubscriber)
{
if(newSubscriber == null) return;
int i = subscribers.indexOf(newSubscriber);
if(i != -1) subscribers.remove(i);
subscribers.add(newSubscriber);
}
/** Returns an unmodifiable Collection of the current subscriber list */
public Collection getSubscribers()
{ return Collections.unmodifiableCollection(subscribers); }
//}}}
//{{{ unsubscribe, unsubscribeAll
//##################################################################################################
/**
* Removes a subscriber from this signal; the subscriber will no
* longer be notified when this signal is activated.
* @return the subscriber that was removed, or null if oldSubscriber was not subscribed
*/
public KinemageSignalSubscriber unsubscribe(KinemageSignalSubscriber oldSubscriber)
{
if(oldSubscriber == null) return null;
int i = subscribers.indexOf(oldSubscriber);
if(i != -1) return (KinemageSignalSubscriber)subscribers.remove(i);
else return null;
}
/**
* Removes all subscribers from this signal's distribution list.
*/
public void unsubscribeAll()
{ subscribers.clear(); }
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KSubgroup.java 0000644 0000000 0000000 00000007053 11531212670 020467 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import javax.swing.tree.*;
//}}}
/**
* KSubgroup
is the KiNG implementation of a Mage subgroup.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 12:10:01 EDT 2002
*/
public class KSubgroup extends AGE implements Cloneable
{
//{{{ Variable definitions
//##################################################################################################
KGroup parent = null;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/** Constructor */
public KSubgroup()
{
children = new ArrayList(10);
setName(null);
}
/** Constructor */
public KSubgroup(KGroup owner, String nm)
{
children = new ArrayList(10);
setOwner(owner);
setName(nm);
}
//}}}
//{{{ clone
//##################################################################################################
/**
* Creates a copy of this group and all its children.
* @param clonePoints whether to clone even the individual points,
* or whether we should use instance= at the list level instead.
*/
public Object clone(boolean clonePoints)
{
try
{
KSubgroup x = (KSubgroup) super.clone(clonePoints);
x.setName( x.getName() ); // tricks it into creating a new JCheckBox object
// Deep copy of children
x.children = new ArrayList();
for(Iterator iter = this.children.iterator(); iter.hasNext(); )
{
KList child = (KList) iter.next();
KList clone = (KList) child.clone(clonePoints);
clone.setOwner(x);
x.add(clone);
}
// Semi-deep copy of masters, which just contains Strings
if(this.masters != null) x.masters = new ArrayList(this.masters);
return x;
}
catch(CloneNotSupportedException ex)
{ throw new Error("Clone failed in cloneable object"); }
}
//}}}
//{{{ get/setOwner()
//##################################################################################################
/** Determines the owner (parent) of this element */
public AGE getOwner()
{ return parent; }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{
parent = (KGroup)owner;
}
//}}}
//{{{ add()
//##################################################################################################
/** Adds a child to this element */
public void add(KList child)
{ children.add(child); }
//}}}
//{{{ MutableTreeNode functions -- insert()
//##################################################################################################
public void insert(MutableTreeNode child, int index)
{
if(! (child instanceof KList)) throw new IllegalArgumentException("Subgroups can only contain lists!");
if(index < 0 || index > children.size()) children.add(child);
else children.add(index, child);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/Kinemage.java 0000644 0000000 0000000 00000074176 11531212670 020300 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import driftwood.data.*;
import java.util.List;
//}}}
/**
* Kinemage
is the top-level container that holds one whole kinemage worth of data.
*
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*
Begun on Fri May 24 21:45:03 EDT 2002
*/
public class Kinemage extends AGE // implements ...
{
//{{{ Variable definitions
//##################################################################################################
/** Called when stuff changes */
public KinemageSignal signal = new KinemageSignal();
/**
* A Map for storing arbitrary information that should be associated with the kinemage.
* Everyone is expected to play nice and use some sort of unique String as a key.
*/
public Map metadata = new HashMap();
// Variables that control the appearance of this kinemage
// These are updated by the user picking from the Display menu
public boolean atWhitebackground = false;
public boolean atOnewidth = false;
public boolean atThinline = false;
public boolean atPerspective = false;
public boolean atFlat = false;
public boolean atListcolordominant = false;
public double atLens = 0.0;
// Other information fields often contained in a kinemage
public String atPdbfile = null;
public String atCommand = null;
// Collection of labels for high-D kins
public Collection dimensionNames = new ArrayList();
// Collection of min,max,min,max,... for high-D kins
public List dimensionMinMax = new ArrayList();
KingView currView = null;
java.util.List viewList = new ArrayList();
float[] boundingBox = null;
float[] center = {0f, 0f, 0f};
float span = 0f;
// For looking up standard and custom colors
Map allColorMap;
Map newColorMap;
Map unmodAllColorMap = null;
Map unmodNewColorMap = null;
// For managing aspects
public Aspect currAspect = null;
java.util.List aspectList = new ArrayList();
// For looking up masters by name
Map mastersMap = new HashMap();
// For iterating thru the masters in order of creation
java.util.List mastersList = new ArrayList();
Component masterSpacer = Box.createRigidArea(new Dimension(0,15));
// For assigning pointmasters to bitfield positions
public String pmLookup = ""; // no pointmasters defined initially
// Each kinemage has its own TreeModel
DefaultTreeModel treeModel;
// For tracking whether edits have been saved
boolean modified = false;
// For storing bondRots
Collection bondRots = null;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new container in the data hierarchy.
*
* @param nm the ID of this group
*/
public Kinemage(String nm)
{
children = new ArrayList(10);
setName(nm);
treeModel = new DefaultTreeModel(this, true);
allColorMap = new UberMap(KPalette.getFullMap());
newColorMap = new UberMap();
}
//}}}
//{{{ appendKinemage
//##################################################################################################
/** Merges a kinemage into this one. That kinemage should be discarded afterwards. */
public void appendKinemage(Kinemage that)
{
atWhitebackground = this.atWhitebackground || that.atWhitebackground;
atOnewidth = this.atOnewidth || that.atOnewidth;
atThinline = this.atThinline || that.atThinline;
atPerspective = this.atPerspective || that.atPerspective;
atFlat = this.atFlat || that.atFlat;
atListcolordominant = this.atListcolordominant || that.atListcolordominant;
if(this.atPdbfile == null) atPdbfile = that.atPdbfile;
if(this.atCommand == null) atCommand = that.atCommand;
//viewList.addAll( that.viewList);
for(Iterator iter = that.viewList.iterator(); iter.hasNext(); )
{
KingView view = (KingView) iter.next();
view.parent = this;
this.viewList.add(view);
}
//aspectList.addAll( that.aspectList);
for(Iterator iter = that.aspectList.iterator(); iter.hasNext(); )
{
Aspect aspect = (Aspect) iter.next();
aspect.parent = this;
this.aspectList.add(aspect);
}
// Merge the colorsets
for(Iterator iter = that.getNewPaintMap().values().iterator(); iter.hasNext(); )
this.addPaint((KPaint)iter.next());
// Merge the masters. This is a little tricky due to pointmasters.
boolean convertPointmasters = false;
for(Iterator iter = that.mastersList.iterator(); iter.hasNext(); )
{
MasterGroup m2 = (MasterGroup)iter.next();
// Convert bitmasks from old kin to new kin correspondences
if(m2.pm_mask != 0)
{
m2.pm_mask = this.toPmBitmask(that.fromPmBitmask(m2.pm_mask), true, false);
convertPointmasters = true;
}
MasterGroup m1 = (MasterGroup)this.mastersMap.get(m2.getName());
if(m1 == null)
{
m2.setOwner(this);
this.mastersMap.put(m2.getName(), m2);
this.mastersList.add(m2);
}
else
{
// This isn't ideal -- what if the bits in m2 are also set
// in some other master belonging to this?
// But it's about the best we can do.
m1.pm_mask |= m2.pm_mask;
}
}
// Finish merging the masters by converting point's pointmaster masks.
// Each point is visited just once b/c instance= lists have no children of their own.
if(convertPointmasters)
{
RecursivePointIterator iter = new RecursivePointIterator(that);
while(iter.hasNext())
{
KPoint p = iter.next();
p.setPmMask(this.toPmBitmask(that.fromPmBitmask(p.getPmMask())));
}
}
for(Iterator iter = that.iterator(); iter.hasNext(); )
{
KGroup group = (KGroup)iter.next();
group.setOwner(this);
this.add(group);
}
// Pass false to avoid removing unused groups, masters in kinemage "this".
// Otherwise, (for instance) we may delete the mobile sidechain used by Chiropraxis tools.
this.initAll(false); // gets us back to a consistent state
}
//}}}
//{{{ get/setOwner, getKinemage
//##################################################################################################
/** Determines the owner (parent) of this element */
public AGE getOwner()
{ return null; }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{}
/** Retrieves the Kinemage object holding this element */
public Kinemage getKinemage()
{ return this; }
//}}}
//{{{ is/setOn, (set)hasButton, is/setDominant
//##################################################################################################
/** Indicates whether this element will paint itself, given the chance */
public boolean isOn()
{ return true; }
/** Sets the painting status of this element */
public void setOn(boolean paint)
{}
/** Indicates whether this element would display a button, given the chance */
public boolean hasButton()
{ return false; }
/** Sets whether this element would display a button, given the chance */
public void setHasButton(boolean b)
{}
/** Indicates whether this element supresses buttons of elements below it */
public boolean isDominant()
{ return false; }
/** Sets whether this element supresses buttons of elements below it */
public void setDominant(boolean b)
{}
//}}}
//{{{ add, replace, initAll, getTreeModel, MutableTreeNode functions
//##################################################################################################
/** Adds a child to this element */
public void add(KGroup child)
{ children.add(child); }
/**
* Replaces oldChild with newChild, or performs an add()
* of newChild if oldChild couldn't be found as part of the kinemage.
* This is very useful for things like Mage's Remote Update.
* @return the group actually replaced, or null for none
*/
public KGroup replace(KGroup oldChild, KGroup newChild)
{
int idx = children.indexOf(oldChild);
if(idx == -1)
{
add(newChild);
return null;
}
else return (KGroup)children.set(idx, newChild);
}
/**
* Convenience function to call after constructing a kinemage from a file
* and before displaying it. This takes care of the following:
*
*- calcSize() -- re-computes size of the kinemage
*- ensureAllMastersExist() -- creates any missing masters
*- syncAllMasters() -- set masters' states appropriately
*- initAllViews() -- converts zooms to spans as necessary
*- animate(0) and animate2(0) -- initializes animations
*
* @param cleanEmpties if true (the default), remove groups/subgroups/lists
* that contain no points and remove unused masters.
*/
public void initAll(boolean cleanEmpties)
{
if(cleanEmpties) removeEmptyAGEs();
calcSize();
ensureAllMastersExist();
if(cleanEmpties) removeUnusedMasters();
syncAllMasters();
initAllViews();
animate(0);
if(!hasAnimateGroups())
animate2(0); // turns off animate group that was just turned on
}
public void initAll()
{ initAll(true); }
public DefaultTreeModel getTreeModel() { return treeModel; }
public void insert(MutableTreeNode child, int index)
{
if(! (child instanceof KGroup)) throw new IllegalArgumentException("Kinemages can only contain groups!");
if(index < 0 || index > children.size()) children.add(child);
else children.add(index, child);
}
public void removeFromParent() {}
//}}}
//{{{ cboxHit, notifyCboxHit, buildButtons
//##################################################################################################
/** Called when the associated checkbox is turned on/off */
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void cboxHit(ActionEvent ev)
{}
/** Propagates notice upward that a checkbox was turned on/off */
public void notifyCboxHit()
{
//kMain.notifyChange(kMain.EM_ON_OFF);
signal.signalKinemage(this, signal.APPEARANCE);
}
/** Builds a grouping of Mage-style on/off buttons in the specified container. */
public Container buildButtons()
{
ensureAllMastersExist();
Box buttonBox = Box.createVerticalBox();
Iterator iter = children.iterator();
while(iter.hasNext())
{
((KGroup)iter.next()).buildButtons(buttonBox);
}
buttonBox.add(masterSpacer);
iter = mastersList.iterator();
while(iter.hasNext())
{
((MasterGroup)iter.next()).buildButtons(buttonBox);
}
return buttonBox;
}
//}}}
//{{{ calcSize, getSpan, getCenter
//##################################################################################################
/**
* Calculates the bounding box and sphere, and center and span of this kinemage.
*/
public void calcSize()
{
// Produces NaN for the center when kinemage is empty
//float[] bounds = { Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
//Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY };
float[] bounds = { Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
-Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE };
calcBoundingBox(bounds);
boundingBox = bounds;
center[0] = (boundingBox[3] + boundingBox[0])/2f;
center[1] = (boundingBox[4] + boundingBox[1])/2f;
center[2] = (boundingBox[5] + boundingBox[2])/2f;
span = 2f * (float)Math.sqrt(calcRadiusSq(center));
if(span == 0) span = 1; // in case there's only one point in the kin
}
/**
* Calculates the span of this kinemage according to the algorithm used by Mage.
* @return the diameter of a sphere that encloses the bounding box that encloses this kinemage
*/
public float getSpan()
{
if(boundingBox == null) calcSize();
return span;
}
/**
* Calculates the center of this kinemage according to the algorithm used by Mage.
* @return the center of the bounding box that encloses this kinemage
*/
public float[] getCenter()
{
if(boundingBox == null) calcSize();
return (float[])center.clone();
}
//}}}
//{{{ getCurrentView, addView, getViewIterator, getViewList, notifyViewSelected, initAllViews
//##################################################################################################
/** Gets the current view for this kinemage */
public KingView getCurrentView()
{
if(currView == null)
{
if(viewList.size() < 1)
{
KingView stdView = new KingView(this);
addView(stdView);
stdView.getSpan(); // converts zoom to span
signal.signalKinemage(this, signal.STRUCTURE);
}
currView = (KingView)((KingView)viewList.get(0)).clone();
}
return currView;
}
/** For use creating new views inside the application. Note: doesn't add v to the viewMap. */
public void addView(KingView v)
{
viewList.add(v);
}
/** Returns an iterator over all the saved views of this kinemage. */
public Iterator getViewIterator() { return viewList.iterator(); }
/**
* Returns a List of all the saved views of this kinemage.
* This list may be modified in order to remove or reorder
* the views present in this kinemage.
*/
public java.util.List getViewList() { return viewList; }
/** Called by a view when the view is picked from a menu */
public void notifyViewSelected(KingView newview)
{
currView = (KingView)newview.clone();
//kMain.notifyChange(kMain.EM_NEWVIEW);
signal.signalKinemage(this, signal.APPEARANCE);
}
/** Calls getSpan() on all views, which converts any values specified as zooms into spans. */
public void initAllViews()
{
KingView v;
for(Iterator iter = this.getViewIterator(); iter.hasNext(); )
{
v = (KingView)iter.next();
v.getSpan();
}
}
//}}}
//{{{ syncAllMasters, ensureMasterExists, ensureAllMastersExist
//##################################################################################################
/** Sets all masters to reflect the state of the group(s) they control */
public void syncAllMasters()
{
for(Iterator iter = mastersList.iterator(); iter.hasNext(); )
{
((MasterGroup)iter.next()).syncState();
}
}
/** Finds a MasterGroup with the given name, creating one if it didn't already exist. */
public void ensureMasterExists(String name)
{
getMasterByName(name);
}
/**
* Builds MasterGroup objects for every master named by a group/subgroup/list.
* This WILL NOT pick up on any pointmasters that aren't also used by one of the above.
*/
public void ensureAllMastersExist()
{
Iterator grIter, suIter, liIter, maIter;
KGroup group;
KSubgroup subgroup;
KList list;
for(grIter = this.iterator(); grIter.hasNext(); )
{
group = (KGroup)grIter.next();
buildMasters(group);
for(suIter = group.iterator(); suIter.hasNext(); )
{
subgroup = (KSubgroup)suIter.next();
buildMasters(subgroup);
for(liIter = subgroup.iterator(); liIter.hasNext(); )
{
list = (KList)liIter.next();
buildMasters(list);
}//lists
}//subgroups
}//groups
}
//}}}
//{{{ buildMasters, getMasterByName, createMaster, masterIter
//##################################################################################################
/** Iterate over all masters in age */
private void buildMasters(AGE age)
{
MasterGroup master;
String masterName;
for(Iterator iter = age.masterIterator(); iter != null && iter.hasNext(); )
{
masterName = iter.next().toString();
if(!mastersMap.containsKey(masterName))
{
master = createMaster(masterName);
// We can call this now, assuming the whole file has been read in
// and all groups to be pasted, have been.
master.syncState();
//System.err.println("Created master '"+masterName+"'");
}
}
}
/** Returns a MasterGroup with the given name, creating one if it didn't already exist. */
public MasterGroup getMasterByName(String name)
{
if(mastersMap.containsKey(name)) return (MasterGroup)mastersMap.get(name);
else return createMaster(name);
}
MasterGroup createMaster(String name)
{
MasterGroup m = new MasterGroup(this, name);
mastersMap.put(name, m);
mastersList.add(m);
return m;
}
/** Returns an unmodifiable Collection of the masters */
public Collection masterList()
{
return Collections.unmodifiableCollection(mastersList);
}
//}}}
//{{{ toPmBitmask, fromPmBitmask
//##################################################################################################
/**
* Converts a string of characters to a bit mask for pointmasters.
* The particular mapping of characters to bits is unique to each kinemage,
* but only up to 32 different characters (case-sensitive) are supported).
* @param addFlags if true, assign unrecognized characters to bit positions,
* but don't necessarily create masters for them. Defaults to false.
* @param addMasters if true, for newly-assigned characters also create
* a master to control that flag. Defaults to false.
*/
public int toPmBitmask(String s, boolean addFlags, boolean addMasters)
{
int i, end_i, bit, mask = 0;
end_i = s.length();
for(i = 0; i < end_i; i++)
{
bit = pmLookup.indexOf(s.charAt(i));
if(bit >= 0 && bit < 32) mask |= 1 << bit;
else if(addFlags && bit == -1)
{
pmLookup = pmLookup+s.charAt(i);
bit = pmLookup.indexOf(s.charAt(i));
if(bit >= 0 && bit < 32) mask |= 1 << bit;
if(addMasters)
{
MasterGroup master = getMasterByName(s.substring(i,i+1));
master.setPmMask(s.substring(i,i+1));
}
}
}
return mask;
}
public int toPmBitmask(String s)
{ return toPmBitmask(s, false, false); }
/** Does the inverse of toPmBitmask() */
public String fromPmBitmask(int mask)
{
StringBuffer result = new StringBuffer();
int probe = 1, end = Math.min(32, pmLookup.length());
for(int i = 0; i < end; i++)
{
if((mask & probe) != 0) result.append(pmLookup.charAt(i));
probe = probe << 1;
}
return result.toString();
}
//}}}
//{{{ animate, animate2, doAnimation
//##################################################################################################
/**
* Drives the animation forward (+1), backward (-1), or to having just one
* group on (0) for all groups marked 'animate'.
* All '2animate' groups are turned off.
*/
public void animate(int incr)
{ doAnimation(getAnimateGroups(), get2AnimateGroups(), incr); }
/**
* Drives the animation forward (+1), backward (-1), or to having just one
* group on (0) for all groups marked '2animate'.
* All 'animate' groups are turned off.
*/
public void animate2(int incr)
{ doAnimation(get2AnimateGroups(), getAnimateGroups(), incr); }
void doAnimation(AGE[] ages, AGE[] offages, int incr)
{
int firstOn = -1;
for(int i = 0; i < ages.length; i++)
{
if(ages[i].isOn())
{
firstOn = i;
break;
}
}
int turnOn = (firstOn == -1 ? 0 : firstOn+incr);
if(turnOn < 0) turnOn = ages.length-1;
else if(turnOn >= ages.length) turnOn = 0;
for(int i = 0; i < ages.length; i++)
ages[i].setOn(i == turnOn);
for(int i = 0; i < offages.length; i++)
offages[i].setOn(false);
}
//}}}
//{{{ accumulate, accumulate2, doAccumulate
//##################################################################################################
/** Turns on the next 'animate' group. '2animate' groups are not affected. */
public void accumulate()
{ doAccumulate(getAnimateGroups()); }
/** Turns on the next '2animate' group. 'animate' groups are not affected. */
public void accumulate2()
{ doAccumulate(get2AnimateGroups()); }
/**
* In order for this to work as expected, we want to turn on the first off group
* that we encounter AFTER the first on group, in a circular way.
*/
void doAccumulate(AGE[] ages)
{
int firstOn = -1;
for(int i = 0; i < ages.length; i++)
{
if(ages[i].isOn())
{
firstOn = i;
break;
}
}
for(int i = firstOn+1; i < firstOn+ages.length; i++)
{
if( !ages[i % ages.length].isOn() )
{
ages[i % ages.length].setOn(true);
break;
}
}
}
//}}}
//{{{ has(2)AnimateGroups, get(2)AnimateGroups
//##################################################################################################
public boolean hasAnimateGroups()
{
for(Iterator iter = children.iterator(); iter.hasNext(); )
{
KGroup group = (KGroup) iter.next();
if(group.isAnimate()) return true;
}
return false;
}
public boolean has2AnimateGroups()
{
for(Iterator iter = children.iterator(); iter.hasNext(); )
{
KGroup group = (KGroup) iter.next();
if(group.is2Animate()) return true;
}
return false;
}
KGroup[] getAnimateGroups()
{
ArrayList animateGroups = new ArrayList();
for(Iterator iter = children.iterator(); iter.hasNext(); )
{
KGroup group = (KGroup) iter.next();
if(group.isAnimate()) animateGroups.add(group);
}
return (KGroup[]) animateGroups.toArray(new KGroup[animateGroups.size()]);
}
KGroup[] get2AnimateGroups()
{
ArrayList animateGroups = new ArrayList();
for(Iterator iter = children.iterator(); iter.hasNext(); )
{
KGroup group = (KGroup) iter.next();
if(group.is2Animate()) animateGroups.add(group);
}
return (KGroup[]) animateGroups.toArray(new KGroup[animateGroups.size()]);
}
//}}}
//{{{ addPaint, getPaintForName, getAll/NewPaintMap
//##################################################################################################
/** Registers the given paint as a legal color for objects in this kinemage. */
public void addPaint(KPaint paint)
{
if(paint == null)
throw new NullPointerException("Can't add a null paint");
allColorMap.put(paint.toString(), paint);
newColorMap.put(paint.toString(), paint);
}
/** Returns the KPaint with the given name, or null if unknown. */
public KPaint getPaintForName(String name)
{
KPaint paint = (KPaint)allColorMap.get(name);
// this will catch things like rust, skyblue, paleyellow, grey, etc.
if(paint == null)
paint = KPalette.forName(name);
return paint;
}
/** Returns an unmodifiable Map<String, KPaint> of known colors */
public Map getAllPaintMap()
{
if(unmodAllColorMap == null)
unmodAllColorMap = Collections.unmodifiableMap(allColorMap);
return unmodAllColorMap;
}
/** Returns an unmodifiable Map<String, KPaint> of colors that have been defined just for this kinemage */
public Map getNewPaintMap()
{
if(unmodNewColorMap == null)
unmodNewColorMap = Collections.unmodifiableMap(newColorMap);
return unmodNewColorMap;
}
//}}}
//{{{ Aspect functions
//##################################################################################################
/** Gets the current aspect for this kinemage (may be null) */
public Aspect getCurrentAspect()
{ return currAspect; }
public void createAspect(String name, Integer index)
{
Aspect a = new Aspect(this, name, index);
aspectList.add(a);
}
/** Returns an iterator over all the saved aspects of this kinemage. */
public ListIterator getAspectIterator() { return aspectList.listIterator(); }
/** Called by an aspect when the aspect is picked from a menu */
public void notifyAspectSelected(Aspect newAspect)
{
currAspect = newAspect;
//kMain.notifyChange(kMain.EM_DISPLAY);
signal.signalKinemage(this, signal.APPEARANCE);
}
//}}}
//{{{ is/setModified
//##################################################################################################
/**
* If true, then the kinemage has been modified since it was loaded
* and the changes have not yet been saved.
* This property is used for save-on-exit traps.
*/
public boolean isModified()
{ return modified; }
/** Sets the value of isModified(). */
public void setModified(boolean b)
{ modified = b; }
//}}}
//{{{ setBondRots, getBondRots
//##################################################################################################
public void setBondRots(Collection br) {
bondRots = br;
}
public Collection getBondRots() {
return bondRots;
}
//}}}
//{{{ removeUnusedMasters
//##################################################################################################
/** Deletes all masters that don't affect any group/subgroup/list/point */
public void removeUnusedMasters()
{
Iterator grIter, suIter, liIter, ptIter;
KGroup group;
KSubgroup subgroup;
KList list;
KPoint point;
Set usedNames = new HashSet();
int pm_mask = 0;
// First, tally all masters and pointmasters
for(grIter = this.iterator(); grIter.hasNext(); )
{
group = (KGroup)grIter.next();
if(group.masters != null) usedNames.addAll(group.masters);
for(suIter = group.iterator(); suIter.hasNext(); )
{
subgroup = (KSubgroup)suIter.next();
if(subgroup.masters != null) usedNames.addAll(subgroup.masters);
for(liIter = subgroup.iterator(); liIter.hasNext(); )
{
list = (KList)liIter.next();
if(list.masters != null) usedNames.addAll(list.masters);
for(ptIter = list.iterator(); ptIter.hasNext(); )
{
point = (KPoint)ptIter.next();
pm_mask |= point.getPmMask();
}//points
}//lists
}//subgroups
}//groups
// Now, remove masters that aren't used
for(Iterator iter = mastersMap.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry e = (Map.Entry) iter.next();
String name = (String) e.getKey();
MasterGroup master = (MasterGroup) e.getValue();
if( !usedNames.contains(name) && (master.pm_mask & pm_mask) == 0)
{
iter.remove();
mastersList.remove(master);
}
}
}
//}}}
//{{{ removeEmptyAGEs
//##################################################################################################
/** Deletes all groups/subgroups/lists that have no points under them */
public void removeEmptyAGEs()
{
Iterator grIter, suIter, liIter;
KGroup group;
KSubgroup subgroup;
KList list;
for(grIter = this.iterator(); grIter.hasNext(); )
{
group = (KGroup)grIter.next();
for(suIter = group.iterator(); suIter.hasNext(); )
{
subgroup = (KSubgroup)suIter.next();
for(liIter = subgroup.iterator(); liIter.hasNext(); )
{
list = (KList)liIter.next();
if(list.children.size() == 0 && list.getInstance() == null) liIter.remove();
}//lists
if(subgroup.children.size() == 0) suIter.remove();
}//subgroups
if(group.children.size() == 0) grIter.remove();
}//groups
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KinWriter.java 0000644 0000000 0000000 00000032246 11531212670 020466 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.Color;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* KinWriter
writes out traditional kinemage files.
*
* Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Thu Oct 3 09:51:11 EDT 2002
*/
public class KinWriter //extends ... implements ...
{
//{{{ Constants
static final DecimalFormat df = driftwood.util.Strings.usDecimalFormat("0.####");
//}}}
//{{{ Variable definitions
//##################################################################################################
PrintWriter out = null;
String lastPointID = null;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public KinWriter()
{
}
//}}}
//{{{ save()
//##################################################################################################
/** Writes out all the currently open kinemages */
public void save(Writer destination, String text, Collection kinemages)
{
Kinemage kin;
int index = 1;
out = new PrintWriter(new BufferedWriter(destination));
out.println("@text");
out.println(text.trim());
for(Iterator iter = kinemages.iterator(); iter.hasNext(); index++)
{
kin = (Kinemage)iter.next();
writeKinemage(kin, index);
}
out.flush();
}
//}}}
//{{{ writeKinemage()
//##################################################################################################
void writeKinemage(Kinemage kin, int index)
{
Iterator iter;
out.println("@kinemage "+index);
if(!kin.getName().startsWith(KinfileParser.DEFAULT_KINEMAGE_NAME))
{ out.println("@title {"+kin.getName()+"}"); }
if(kin.atWhitebackground) out.println("@whitebackground");
if(kin.atOnewidth) out.println("@onewidth");
else if(kin.atThinline) out.println("@thinline");
if(kin.atPerspective) out.println("@perspective");
if(kin.atFlat) out.println("@flat");
if(kin.atListcolordominant) out.println("@listcolordominant");
if(kin.atLens > 0.0) out.println("@lens "+df.format(kin.atLens));
if(kin.atPdbfile != null) out.println("@pdbfile {"+kin.atPdbfile+"}");
if(kin.atCommand != null) out.println("@command {"+kin.atCommand+"}");
Collection colorsets = kin.getNewPaintMap().values();
for(iter = colorsets.iterator(); iter.hasNext(); )
{
KPaint paint = (KPaint)iter.next();
if(paint.isAlias())
out.println("@colorset {"+paint+"} "+paint.getAlias());
else
{
//out.println("< Couldn't save new color "+paint+" >");
out.print("@hsvcolor {"+paint+"}");
Color color = (Color) paint.getBlackExemplar();
float[] hsv = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
out.print(" "+df.format(360*hsv[0])+" "+df.format(100*hsv[1])+" "+df.format(100*hsv[2]));
color = (Color) paint.getWhiteExemplar();
hsv = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
out.print(" "+df.format(360*hsv[0])+" "+df.format(100*hsv[1])+" "+df.format(100*hsv[2]));
out.println();
}
}
Aspect aspect;
for(iter = kin.getAspectIterator(); iter.hasNext(); )
{
aspect = (Aspect)iter.next();
out.println("@"+aspect.getIndex()+"aspect {"+aspect.getName()+"}");
}
int idx = 1;
for(iter = kin.getViewIterator(); iter.hasNext(); idx++)
{
writeView((KingView)iter.next(), idx);
}
for(iter = kin.masterList().iterator(); iter.hasNext(); )
{
writeMaster((MasterGroup)iter.next(), kin);
}
if(kin.dimensionNames.size() > 0)
{
out.print("@dimensions");
for(iter = kin.dimensionNames.iterator(); iter.hasNext(); )
out.print(" {"+iter.next()+"}");
out.println();
}
if(kin.dimensionMinMax.size() > 0)
{
out.print("@dimminmax");
for(iter = kin.dimensionMinMax.iterator(); iter.hasNext(); )
out.print(" "+df.format(((Number)iter.next()).doubleValue()));
out.println();
}
// etc.
KGroup group;
for(iter = kin.iterator(); iter.hasNext(); )
{
group = (KGroup)iter.next();
writeGroup(group, kin);
}
}
//}}}
//{{{ writeGroup()
//##################################################################################################
void writeGroup(KGroup group, Kinemage kin)
{
Iterator iter;
out.print("@group {"+group.getName()+"}");
if(! group.isOn()) out.print(" off");
if(! group.hasButton()) out.print(" nobutton");
if( group.isDominant()) out.print(" dominant");
if( group.isRecessiveOn()) out.print(" recessiveon");
if( group.isAnimate()) out.print(" animate");
if( group.is2Animate()) out.print(" 2animate");
if( group.isLens()) out.print(" lens");
/*MasterGroup master;
for(iter = kin.masterIter(); iter.hasNext(); )
{
master = (MasterGroup)iter.next();
if(master.isTarget(group)) out.print(" master= {"+master.getName()+"}");
}*/
for(iter = group.masterIterator(); iter != null && iter.hasNext(); )
{
out.print(" master= {"+iter.next().toString()+"}");
}
out.println();
KSubgroup subgroup;
for(iter = group.iterator(); iter.hasNext(); )
{
subgroup = (KSubgroup)iter.next();
writeSubgroup(subgroup, kin);
}
}
//}}}
//{{{ writeSubgroup()
//##################################################################################################
void writeSubgroup(KSubgroup subgroup, Kinemage kin)
{
Iterator iter;
out.print("@subgroup {"+subgroup.getName()+"}");
if(! subgroup.isOn()) out.print(" off");
if(! subgroup.hasButton()) out.print(" nobutton");
if( subgroup.isDominant()) out.print(" dominant");
if( subgroup.isRecessiveOn()) out.print(" recessiveon");
if( subgroup.isLens()) out.print(" lens");
/*MasterGroup master;
for(iter = kin.masterIter(); iter.hasNext(); )
{
master = (MasterGroup)iter.next();
if(master.isTarget(subgroup)) out.print(" master= {"+master.getName()+"}");
}*/
for(iter = subgroup.masterIterator(); iter != null && iter.hasNext(); )
{
out.print(" master= {"+iter.next().toString()+"}");
}
out.println();
KList list;
for(iter = subgroup.iterator(); iter.hasNext(); )
{
list = (KList)iter.next();
writeList(list, kin);
}
}
//}}}
//{{{ writeList()
//##################################################################################################
void writeList(KList list, Kinemage kin)
{
Iterator iter;
out.print("@"+list.getType()+"list {"+list.getName()+"}");
if(list.getInstance() != null)
out.print(" instance= {"+list.getInstance().getName()+"}");
if(! list.isOn()) out.print(" off");
if(! list.hasButton()) out.print(" nobutton");
if( list.isLens()) out.print(" lens");
KPaint paint = list.getColor();
if(paint == null) paint = KPalette.defaultColor;
if(paint.isAlias()) out.print(" color= {"+paint+"}");
else out.print(" color= "+paint);
if(list.getType() == KList.VECTOR || list.getType() == KList.DOT)
{
if(list.width != 2) out.print(" width= "+list.width);
}
else if(list.getType() == KList.BALL || list.getType() == KList.SPHERE || list.getType() == KList.RING)
{
out.print(" radius= "+df.format(list.radius));
if((list.flags & KList.NOHILITE) != 0) out.print(" nohilite");
}
else if(list.getType() == KList.ARROW)
{
out.print(" radius= "+df.format(list.getRadius()));
out.print(" angle= "+df.format(list.getAngle()));
}
if(list.alpha != 255) out.print(" alpha= "+df.format(list.alpha/255.0));
for(iter = list.masterIterator(); iter != null && iter.hasNext(); )
{
out.print(" master= {"+iter.next().toString()+"}");
}
if(list.getDimension() != 3) out.print(" dimension= "+list.getDimension());
out.println();
KPoint point;
lastPointID = null;
for(iter = list.iterator(); iter.hasNext(); )
{
point = (KPoint)iter.next();
writePoint(point, list, kin);
lastPointID = point.getName();
}
}
//}}}
//{{{ writePoint()
//##################################################################################################
void writePoint(KPoint point, KList list, Kinemage kin)
{
Iterator iter;
if(point.getComment() != null) out.print("<"+point.getComment()+">");
String pointID = point.getName();
if(pointID.equals(lastPointID)) out.print("{\"}");
else out.print("{"+pointID+"}");
if(point.getPmMask() != 0) out.print("'"+kin.fromPmBitmask(point.getPmMask())+"' ");
if(point.getAspects() != null) out.print("("+point.getAspects()+") ");
if(point.isBreak()) out.print("P ");
if(point.isUnpickable()) out.print("U ");
if(point.isGhost()) out.print("ghost ");
if(point instanceof TrianglePoint && point.isBreak())
out.print("X "); // because triangle- and ribbonlists don't break for P
else if(point instanceof VectorPoint)
{
VectorPoint v = (VectorPoint)point;
if(v.width > 0 && v.width != list.width) out.print("width"+v.width+" ");
}
else if(point instanceof BallPoint)
{
BallPoint b = (BallPoint)point;
if(b.r0 > 0f) out.print("r="+df.format(b.r0)+" ");
}
else if(point instanceof MarkerPoint)
{
MarkerPoint m = (MarkerPoint)point;
if(m.getStyle() != 0) out.print("s="+m.getStyle()+" ");
}
/* XXX-DEBUG * /
else if(point instanceof TrianglePoint)
{
if((point.multi & point.SEQ_EVEN_BIT) != 0) out.print(" ");
else out.print(" ");
}
/* XXX-DEBUG */
KPaint paint = point.getColor();
if(paint != null && paint != list.getColor())
out.print(paint+" ");
float[] coords = point.getAllCoords();
if(coords == null)
out.println(df.format(point.getOrigX())+" "+df.format(point.getOrigY())+" "+df.format(point.getOrigZ()));
else
{
for(int i = 0; i < coords.length; i++) out.print(df.format(coords[i])+" ");
out.println();
}
}
//}}}
//{{{ writeView(), writeMaster()
//##################################################################################################
void writeView(KingView view, int index)
{
out.println("@"+index+"viewid {"+view.getName()+"}");
out.println("@"+index+"span "+view.getSpan());
out.println("@"+index+"zslab "+(view.getClip()*200f));
float[] center = view.getCenter();
out.println("@"+index+"center "+df.format(center[0])+" "+df.format(center[1])+" "+df.format(center[2]));
int[] axes = view.getViewingAxes();
if(axes != null)
out.println("@"+index+"axischoice "+(axes[0]+1)+" "+(axes[1]+1)+" "+(axes[2]+1));
// Writen out Mage-style, for a post-multiplied matrix
out.print("@"+index+"matrix");
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++) out.print(" "+df.format(view.xform[j][i]));
}
out.println();
}
void writeMaster(MasterGroup master, Kinemage kin)
{
out.print("@master {"+master.getName()+"}");
//if(! master.isOn()) out.print(" off");
if(! master.hasButton()) out.print(" nobutton");
if(master.indent) out.print(" indent");
out.println();
if(master.pm_mask != 0)
{
out.println("@pointmaster '"+kin.fromPmBitmask(master.pm_mask)+"' {"+master.getName()+"}");
}
}
///}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KPoint.java 0000644 0000000 0000000 00000023717 11531212670 017757 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* KPoint
is a generic, non-instantiable representation of a 'point' in a kinemage.
* This class and its subclasses contain the code for drawing all the different graphics primitives in Mage.
*
* Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 12:57:57 EDT 2002
*/
public interface KPoint extends AHE, Cloneable, MutableTuple3
{
//{{{ Constants
//}}}
//{{{ clone
//##################################################################################################
public Object clone();
//}}}
//{{{ get/setOrigX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getX(). */
public float getOrigX();
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getY(). */
public float getOrigY();
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getZ). */
public float getOrigZ();
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setX(). */
public void setOrigX(double xx);
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setY(). */
public void setOrigY(double yy);
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setZ(). */
public void setOrigZ(double zz);
/** Assigns a value to the untransformed coordinates for this point.
* @deprecated In favor of setXYZ(). */
public void setOrigXYZ(Tuple3 t);
//}}}
//{{{ get/setX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point */
public double getX();
/** Returns the untransformed coordinate for this point */
public double getY();
/** Returns the untransformed coordinate for this point */
public double getZ();
/** Assigns a value to the untransformed coordinate for this point */
public void setX(double xx);
/** Assigns a value to the untransformed coordinate for this point */
public void setY(double yy);
/** Assigns a value to the untransformed coordinate for this point */
public void setZ(double zz);
/** Assigns a value to the untransformed coordinates for this point */
public void setXYZ(double xx, double yy, double zz);
//}}}
//{{{ get/setDrawX/Y/Z
//##################################################################################################
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawX();
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawY();
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawZ();
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawX(double xx);
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawY(double yy);
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawZ(double zz);
/** Assigns a value to the fully transformed (drawing) coordinates for this point */
public void setDrawXYZ(Tuple3 t);
//}}}
//{{{ get/setAllCoords, useCoordsXYZ
//##################################################################################################
/**
* Stores an array of coordinates for "high-dimensional" points.
* The float[] is stored without cloning and so is subject to overwrite.
*/
public void setAllCoords(float[] coords);
/**
* Retrieves the "high-dimensional" coordinates of this point, or null if not set.
* The float[] is returned without cloning and so is subject to overwrite.
*/
public float[] getAllCoords();
/**
* Copies the high-dimensional coordinates at the specified indices
* into this point's (untransformed) X, Y, and Z fields.
* If a index is out of range (0-based), it is ignored and the value is not changed.
*/
public void useCoordsXYZ(int xIndex, int yIndex, int zIndex);
//}}}
//{{{ get/setPrev, isBreak
//##################################################################################################
/**
* Sets the point that precedes this one.
* This matters to "chainable" points, like vectors and triangles.
* For other points, it does nothing.
* @param pt the point preceding this one in seqence
*/
public void setPrev(KPoint pt);
/**
* Gets the point preceding this one in the chain.
* @return the preceding point, or null if (a) this is a break in the chain or (b) this is not a chainable point type.
*/
public KPoint getPrev();
/**
* True iff this is a chainable point type (e.g. vector, triangle) AND there is a chain break.
*/
public boolean isBreak();
//}}}
//{{{ is/get/set{On, Unpickable, Ghost, Color, Aspects, Width, Radius, Comment}
//##################################################################################################
/** Indicates whether this point can be picked with the mouse */
public boolean isUnpickable();
/** Sets the picking status of this point */
public void setUnpickable(boolean b);
/** Indicates whether this point is a "ghost" for Mage */
public boolean isGhost();
/** Sets the ghost status of this point */
public void setGhost(boolean b);
/** Returns the color of this point, or null if it inherits from its list */
public KPaint getColor();
/** Sets the color of this point. */
public void setColor(KPaint c);
/** Gets the aspect string of this point */
public String getAspects();
/** Sets the aspect string of this point */
public void setAspects(String a);
/** Gets the line width of this point, if applicable */
public int getWidth();
/** Sets the line width of this point, if applicable */
public void setWidth(int w);
/** Gets the radius of this point, if applicable */
public float getRadius();
/** Sets the radius of this point, if applicable */
public void setRadius(float radius);
/** Sets the point comment for this point. */
public void setComment(String cmt);
/** Gets the comment for this point, which defaults to null. */
public String getComment();
//}}}
//{{{ getDrawingColor
//##################################################################################################
/** Returns the color that will be used to draw this point (ignoring aspects). Never null. */
public KPaint getDrawingColor();
/** Returns the color that will be used to draw this point, taking aspects into account. Never null. */
public KPaint getDrawingColor(Engine engine);
//}}}
//{{{ pmHit, pmWouldHit, get/setPmMask
//##################################################################################################
/**
* Processes a pointmaster on/off request.
* @param mask the bitmask indicating which masters are being turned on/off
* @param offmask the bitmask indicating which masters are already off
* @param turnon true
if affected points are to be turned on,
* false
if affected points are to be turned off.
*/
public void pmHit(int mask, int offmask, boolean turnon);
/** Indicates whether or not the given pointmaster set would affect this point. */
public boolean pmWouldHit(int mask);
public int getPmMask();
public void setPmMask(int mask);
//}}}
//{{{ signalTransform
//##################################################################################################
public void signalTransform(Engine engine, Transform xform);
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom);
//}}}
//{{{ paintStandard, isPickedBy
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine);
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick);
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/SpherePoint.java 0000644 0000000 0000000 00000012015 11531212670 021000 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* SpherePoint
is like a BallPoint, except it renders a whole stack
* of disks like Mage does for @spherelists.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Mon Oct 18 10:26:11 EDT 2004
*/
public class SpherePoint extends BallPoint
{
//{{{ Constants
static final int N_DISKS = 16;
static final double[] sin = new double[N_DISKS];
static final double[] cos = new double[N_DISKS];
static
{
// Sin is fwd offset from largest disk, moving toward viewer.
// Sin spacing is such that disk spacing is equal.
// Cos is for scaling disk radius.
for(int i = 0; i < N_DISKS; i++)
{
sin[i] = (double)i/(double)N_DISKS;
cos[i] = Math.sqrt(1.0 - sin[i]*sin[i]);
}
}
//}}}
//{{{ CLASS: DiskProxyPoint
//##############################################################################
/**
* DiskProxyPoint is used to represent one disk in the stack for drawing and
* picking purposes only.
*/
static class DiskProxyPoint extends ProxyPoint
{
int diskLevel;
public DiskProxyPoint(BallPoint proxyFor, int diskLevel)
{
super(proxyFor);
this.diskLevel = diskLevel;
}
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
// Don't use alpha, b/c it won't look right for stacked disks
Paint paint = maincolor.getPaint(engine.backgroundMode, SpherePoint.sin[diskLevel], engine.colorCue, 255);
double r = SpherePoint.cos[diskLevel] * ((BallPoint)proxyFor).r;
engine.painter.paintSphereDisk(paint, getDrawX(), getDrawY(), getDrawZ(), r);
}
}
//}}}
//{{{ Variable definitions
//##############################################################################
DiskProxyPoint[] proxies;
//}}}
//{{{ Constructor(s)
//##############################################################################
public SpherePoint(KList list, String label)
{
super(list, label);
// Need one less b/c "this" acts as the base layer
this.proxies = new DiskProxyPoint[N_DISKS-1];
for(int i = 1; i < N_DISKS; i++)
{
this.proxies[i-1] = new DiskProxyPoint(this, i);
}
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
super.signalTransform(engine, xform, zoom);
// "this" has already been added at i == 0
for(int i = 1; i < N_DISKS; i++)
{
engine.addPaintable(proxies[i-1], z + sin[i]*r);
}
}
//}}}
//{{{ paintStandard
//##############################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
// Don't use alpha, b/c it won't look right for stacked disks
Paint paint = maincolor.getPaint(engine.backgroundMode, 0, engine.colorCue, 255);
// Can't do depth cueing by width -- causes really weird problems!!
//
// We have to do this here b/c now widthCue is set
//if(engine.cueThickness) r *= KPalette.widthScale[ engine.widthCue ];
engine.painter.paintSphereDisk(paint, x, y, z, r);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/ArrowPoint.java 0000644 0000000 0000000 00000014344 11531212670 020653 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* ArrowPoint
represents the endpoint of a line
* and has an arrowhead on it.
*
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*
Begun on Fri Apr 26 16:46:09 EDT 2002
*/
public class ArrowPoint extends VectorPoint // implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a new data point representing one end of a line.
*
* @param list the list that contains this point
* @param label the pointID of this point
* @param start where this line is drawn from, or null if it's the starting point
*/
public ArrowPoint(KList list, String label, VectorPoint start)
{
super(list, label, start);
}
//}}}
//{{{ paintStandard2
//##################################################################################################
/**
* This function exists solely for the convenience of ArrowPoints;
* a good JIT will optimize it away for VectorPoints.
* Coordinates are already transformed, perspective corrected, and clipped by Z planes.
* They have NOT been clipped to the drawing area yet.
*/
void paintStandard2(Engine engine, Paint paint, double fromX, double fromY, double fromZ, double toX, double toY, double toZ)
{
int lineWidth = calcLineWidth(engine);
// Arrow tines are faked at the real "to" endpoint OR at the edge of the screen.
// Each tine is a vector with a component perpedicular to the arrow body and a component parallel.
// The parallel is foreshortened by the dot product of the body with <0,0,1>;
// the perpendicular is unchanged, which keeps the arrow "facing" the screen as much as possible.
// Perspective effects are ignored b/c the arrowheads are small.
double tinePerp = 10, tinePar = 20; // in pixels
if(parent != null)
{
tinePerp = parent.tinePerp * engine.zoom3D;
tinePar = parent.tinePar * engine.zoom3D;
}
// Unit vector from arrow head toward arrow tail
engine.work1.setXYZ( fromX-toX, fromY-toY, fromZ-toZ );
if(engine.work1.mag2() < 1e-10) engine.work1.setXYZ(0,0,1);
else engine.work1.unit();
// Z vector and dot product (for foreshortening of tines)
engine.work2.setXYZ(0,0,1);
tinePar *= 1 - Math.abs( engine.work2.dot(engine.work1) );
// Unit vector from arrow head toward arrow tail, in the plane of the screen!
engine.work1.setXYZ( fromX-toX, fromY-toY, 0 );
if(engine.work1.mag2() < 1e-10) engine.work1.setXYZ(1,0,0);
else engine.work1.unit();
// "To" ends of the line (where arrow head is drawn) must be clipped to
// the edges of the screen so we can see outbound arrows when zoomed in.
// This code ignores Z, which is why we calc'd foreshortening first.
// We use the Cohen-Sutherland algorithm for clipping a line to a box.
// Int flags represent being out of bounds on each of four sides:
final int LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8;
final double xmin = engine.pickingRect.x, ymin = engine.pickingRect.y;
final double xmax = xmin+engine.pickingRect.width, ymax = ymin+engine.pickingRect.height;
int toOutcode = 0, fromOutcode = 0;
if(toX < xmin) toOutcode |= LEFT;
else if(toX > xmax) toOutcode |= RIGHT;
if(toY < ymin) toOutcode |= TOP;
else if(toY > ymax) toOutcode |= BOTTOM;
if(fromX < xmin) fromOutcode |= LEFT;
else if(fromX > xmax) fromOutcode |= RIGHT;
if(fromY < ymin) fromOutcode |= TOP;
else if(fromY > ymax) fromOutcode |= BOTTOM;
// If outcode is zero, the point is inside the clipping region.
// If the AND of the outcodes is nonzero, thw whole line is outside the clipping region.
if(toOutcode != 0 && (toOutcode & fromOutcode) == 0)
{
//paint = Color.red;
if(toX < xmin)
{
toY = fromY + (toY-fromY)*(xmin-fromX)/(toX-fromX);
toX = xmin;
}
else if(toX > xmax)
{
toY = fromY + (toY-fromY)*(xmax-fromX)/(toX-fromX);
toX = xmax;
}
// Even though we've corrected the side-to-side clipping,
// the top-to-bottom clipping may also need work
// (e.g. if we're projecting out thru a corner of the canvas)
if(toY < ymin)
{
toX = fromX + (toX-fromX)*(ymin-fromY)/(toY-fromY);
toY = ymin;
}
else if(toY > ymax)
{
toX = fromX + (toX-fromX)*(ymax-fromY)/(toY-fromY);
toY = ymax;
}
}
// (-y,x) and (y,-x) are orthogonal to (x,y)
// x and y offsets each have components from perpedicular and parallel.
double dx, dy;
dx = tinePar*engine.work1.getX() - tinePerp*engine.work1.getY();
dy = tinePar*engine.work1.getY() + tinePerp*engine.work1.getX();
engine.painter.paintVector(paint, lineWidth, engine.widthCue,
toX, toY, toZ, toX+dx, toY+dy, toZ);
dx = tinePar*engine.work1.getX() + tinePerp*engine.work1.getY();
dy = tinePar*engine.work1.getY() - tinePerp*engine.work1.getX();
engine.painter.paintVector(paint, lineWidth, engine.widthCue,
toX, toY, toZ, toX+dx, toY+dy, toZ);
// Main arrow body
engine.painter.paintVector(paint, lineWidth, engine.widthCue,
fromX, fromY, fromZ, toX, toY, toZ);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/HighQualityPainter.java 0000644 0000000 0000000 00000012646 11531212670 022325 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.geom.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* HighQualityPainter
paints kinemage graphics using the new-style
* Shape calls from a java.awt.Graphics2D object.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Fri May 21 19:20:49 EDT 2004
*/
public class HighQualityPainter extends StandardPainter
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
Line2D.Double line1 = new Line2D.Double();
Ellipse2D.Double ellipse1 = new Ellipse2D.Double();
GeneralPath path1 = new GeneralPath();
//}}}
//{{{ Constructor(s)
//##############################################################################
public HighQualityPainter(boolean forceAntialiasing)
{
super(forceAntialiasing);
}
//}}}
//{{{ paintBall
//##################################################################################################
public void paintBall(Paint paint, double x, double y, double z, double r, boolean showHighlight)
{
if(r < 0.5) r = 0.5; // make sure balls don't disappear
double d = 2.0*r;
// one disk
g.setPaint(paint);
g.setStroke(KPalette.pen0);
ellipse1.setFrame((x-r), (y-r), d, d);
if(REALLY_PAINT) g.fill(ellipse1);
// Black rim, causes ~10% speed penalty but useful for visualization!
try
{
Color c = (Color) paint;
if(d >= 10 && c.getAlpha() == 255)
{
g.setPaint(KPaint.black); // wants to merge with the background
g.setStroke(KPalette.pen1);
if(REALLY_PAINT) g.draw(ellipse1);
}
}
catch(ClassCastException ex)
{
ex.printStackTrace();
System.err.println("HighQualityPainter: tried painting with non-Color type of Paint");
}
// highlight
if(showHighlight)
{
double off = 0.5 * r;
d = 0.3*r;
g.setPaint(Color.white); // wants to be bright white no matter what
g.setStroke(KPalette.pen0);
ellipse1.setFrame((x-off), (y-off), d, d);
if(REALLY_PAINT) g.fill(ellipse1);
}
}
//}}}
//{{{ paintDot
//##################################################################################################
public void paintDot(Paint paint, double x, double y, double z, int width)
{
int off = width/2;
g.setPaint(paint);
g.setStroke(KPalette.pen0);
ellipse1.setFrame((x-off), (y-off), width, width);
if(REALLY_PAINT) g.fill(ellipse1);
}
//}}}
//{{{ paintSphereDisk
//##################################################################################################
public void paintSphereDisk(Paint paint, double x, double y, double z, double r)
{
if(r < 0.5) r = 0.5; // make sure balls don't disappear
double d = 2.0*r;
// one disk
g.setPaint(paint);
g.setStroke(KPalette.pen0);
ellipse1.setFrame((x-r), (y-r), d, d);
if(REALLY_PAINT) g.fill(ellipse1);
}
//}}}
//{{{ paintTriangle
//##################################################################################################
public void paintTriangle(Paint paint,
double x1, double y1, double z1,
double x2, double y2, double z2,
double x3, double y3, double z3)
{
g.setPaint(paint);
g.setStroke(KPalette.pen1);
path1.reset();
path1.moveTo((float)x1, (float)y1);
path1.lineTo((float)x2, (float)y2);
path1.lineTo((float)x3, (float)y3);
path1.closePath();
if(REALLY_PAINT)
{
g.fill(path1);
g.draw(path1); // closes up the hairline cracks between triangles (?)
}
}
//}}}
//{{{ paintVector
//##################################################################################################
public void paintVector(Paint paint, int width, int widthCue,
double x1, double y1, double z1,
double x2, double y2, double z2)
{
g.setPaint(paint);
g.setStroke(KPalette.pens[width-1][widthCue]);
line1.setLine(x1, y1, x2, y2);
if(REALLY_PAINT) g.draw(line1);
}
//}}}
//{{{ drawOval
//##################################################################################################
public void drawOval(Paint paint, double x, double y, double z, double width, double height)
{
g.setPaint(paint);
g.setStroke(KPalette.pen1);
ellipse1.setFrame((x - width/2), (y - height/2), width, height);
if(REALLY_PAINT) g.draw(ellipse1);
}
public void drawOval(Paint paint, int linewidth, int widthCue, double x, double y, double z, double width, double height)
{
g.setPaint(paint);
g.setStroke(KPalette.pens[linewidth-1][widthCue]);
ellipse1.setFrame((x - width/2), (y - height/2), width, height);
if(REALLY_PAINT) g.draw(ellipse1);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/ParaPoint.java 0000644 0000000 0000000 00000037276 11531212670 020455 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* ParaPoint
is proxy point used for parallel coordinates.
*
*
Copyright (C) 2006 by Ian W. Davis. All rights reserved.
*
Begun on Fri Nov 17 11:34:49 EST 2006
*/
public class ParaPoint extends VectorPoint
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
KPoint proxyFor;
int dimIdx;
ParaParams params;
//}}}
//{{{ Constructor(s)
//##############################################################################
/**
* Creates a new data point representing one end of a line.
*
* @param proxyFor the (Ball)Point that this line represents
* @param dimIdx the dimension / axis of proxyFor to represent, from 0 ... D
* (Could probably be figured by tracing back along start.)
* @param start where this line is drawn from, or null if it's the starting point
*/
public ParaPoint(KPoint proxyFor, int dimIdx, ParaPoint start, ParaParams params)
{
super((KList)proxyFor.getOwner(), proxyFor.getName(), start);
this.proxyFor = proxyFor;
this.dimIdx = dimIdx;
this.params = params;
syncCoords();
}
//}}}
//{{{ syncCoords
//##############################################################################
protected void syncCoords()
{
float[] allCoords = proxyFor.getAllCoords();
if(allCoords == null || allCoords.length <= dimIdx)
throw new IllegalArgumentException("Not enough coordinates in proxy to support parallel coords");
this.x0 = (float) (1.0 * dimIdx / (params.getNumDim() - 1)); // [0, 1]
this.y0 = (float) ((allCoords[dimIdx] - params.getMin(dimIdx)) / params.getRange(dimIdx)); // [0, 1]
this.z0 = 0; // may use this for something later, not now
}
//}}}
//{{{ get/setOrigX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getX(). */
public float getOrigX() { return (float) this.getX(); }
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getY(). */
public float getOrigY() { return (float) this.getY(); }
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getZ). */
public float getOrigZ() { return (float) this.getZ(); }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setX(). */
public void setOrigX(double xx) { this.setX(xx); }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setY(). */
public void setOrigY(double yy) { this.setY(yy); }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setZ(). */
public void setOrigZ(double zz) { this.setZ(zz); }
/** Assigns a value to the untransformed coordinates for this point.
* @deprecated In favor of setXYZ(). */
public void setOrigXYZ(Tuple3 t) {}
//}}}
//{{{ get/setX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point */
//public double getX() { return proxyFor.getX(); }
/** Returns the untransformed coordinate for this point */
//public double getY() { return proxyFor.getY(); }
/** Returns the untransformed coordinate for this point */
//public double getZ() { return proxyFor.getZ(); }
/** Assigns a value to the untransformed coordinate for this point */
public void setX(double xx) {}
/** Assigns a value to the untransformed coordinate for this point */
public void setY(double yy) {}
/** Assigns a value to the untransformed coordinate for this point */
public void setZ(double zz) {}
/** Assigns a value to the untransformed coordinates for this point */
public void setXYZ(double xx, double yy, double zz) {}
//}}}
//{{{ get/setDrawX/Y/Z
//##################################################################################################
/** Returns the fully transformed (drawing) coordinate for this point */
//public float getDrawX() { return proxyFor.getDrawX(); }
/** Returns the fully transformed (drawing) coordinate for this point */
//public float getDrawY() { return proxyFor.getDrawY(); }
/** Returns the fully transformed (drawing) coordinate for this point */
//public float getDrawZ() { return proxyFor.getDrawZ(); }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
//public void setDrawX(double xx) { proxyFor.setDrawX(xx); }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
//public void setDrawY(double yy) { proxyFor.setDrawY(yy); }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
//public void setDrawZ(double zz) { proxyFor.setDrawZ(zz); }
/** Assigns a value to the fully transformed (drawing) coordinates for this point */
//public void setDrawXYZ(Tuple3 t) { proxyFor.setDrawXYZ(t); }
//}}}
//{{{ get/setAllCoords, useCoordsXYZ
//##################################################################################################
/**
* Stores an array of coordinates for "high-dimensional" points.
* The float[] is stored without cloning and so is subject to overwrite.
*/
//public void setAllCoords(float[] coords) { proxyFor.setAllCoords(coords); }
/**
* Retrieves the "high-dimensional" coordinates of this point, or null if not set.
* The float[] is returned without cloning and so is subject to overwrite.
*/
//public float[] getAllCoords() { return proxyFor.getAllCoords(); }
/**
* Copies the high-dimensional coordinates at the specified indices
* into this point's (untransformed) X, Y, and Z fields.
* If a index is out of range (0-based), it is ignored and the value is not changed.
*/
public void useCoordsXYZ(int xIndex, int yIndex, int zIndex) { proxyFor.useCoordsXYZ(xIndex, yIndex, zIndex); }
//}}}
//{{{ get/setPrev, isBreak
//##################################################################################################
/**
* Sets the point that precedes this one.
* This matters to "chainable" points, like vectors and triangles.
* For other points, it does nothing.
* @param pt the point preceding this one in seqence
*/
//public void setPrev(KPoint pt) { proxyFor.setPrev(pt); }
/**
* Gets the point preceding this one in the chain.
* @return the preceding point, or null if (a) this is a break in the chain or (b) this is not a chainable point type.
*/
//public KPoint getPrev() { return proxyFor.getPrev(); }
/**
* True iff this is a chainable point type (e.g. vector, triangle) AND there is a chain break.
*/
//public boolean isBreak() { return proxyFor.isBreak(); }
//}}}
//{{{ is/get/set{On, Unpickable, Ghost, Color, Aspects, Width, Radius, Comment}
//##################################################################################################
/** Indicates whether this element will paint itself, given the chance */
public boolean isOn() { return proxyFor.isOn(); }
/** Sets the painting status of this element */
public void setOn(boolean paint) { proxyFor.setOn(paint); }
/** Indicates whether this point can be picked with the mouse */
public boolean isUnpickable() { return proxyFor.isUnpickable(); }
/** Sets the picking status of this point */
public void setUnpickable(boolean b) { proxyFor.setUnpickable(b); }
/** Indicates whether this point is a "ghost" for Mage */
public boolean isGhost() { return proxyFor.isGhost(); }
/** Sets the ghost status of this point */
public void setGhost(boolean b) { proxyFor.setGhost(b); }
/** Returns the color of this point, or null if it inherits from its list */
public KPaint getColor() { return proxyFor.getColor(); }
/** Sets the color of this point. */
public void setColor(KPaint c) { proxyFor.setColor(c); }
/** Gets the aspect string of this point */
public String getAspects() { return proxyFor.getAspects(); }
/** Sets the aspect string of this point */
public void setAspects(String a) { proxyFor.setAspects(a); }
/** Gets the line width of this point, if applicable */
//public int getWidth() { return proxyFor.getWidth(); }
/** Sets the line width of this point, if applicable */
//public void setWidth(int w) { proxyFor.setWidth(w); }
/** Gets the radius of this point, if applicable */
public float getRadius() { return proxyFor.getRadius(); }
/** Sets the radius of this point, if applicable */
public void setRadius(float radius) { proxyFor.setRadius(radius); }
/** Sets the point comment for this point. */
public void setComment(String cmt) { proxyFor.setComment(cmt); }
/** Gets the comment for this point, which defaults to null. */
public String getComment() { return proxyFor.getComment(); }
//}}}
//{{{ getDrawingColor
//##################################################################################################
/** Returns the color that will be used to draw this point (ignoring aspects). Never null. */
public KPaint getDrawingColor() { return proxyFor.getDrawingColor(); }
/** Returns the color that will be used to draw this point, taking aspects into account. Never null. */
public KPaint getDrawingColor(Engine engine) { return proxyFor.getDrawingColor(engine); }
//}}}
//{{{ pmHit, pmWouldHit, get/setPmMask
//##################################################################################################
/**
* Processes a pointmaster on/off request.
* @param mask the bitmask indicating which masters are being turned on/off
* @param offmask the bitmask indicating which masters are already off
* @param turnon true
if affected points are to be turned on,
* false
if affected points are to be turned off.
*/
public void pmHit(int mask, int offmask, boolean turnon) { proxyFor.pmHit(mask, offmask, turnon); }
/** Indicates whether or not the given pointmaster set would affect this point. */
public boolean pmWouldHit(int mask) { return proxyFor.pmWouldHit(mask); }
public int getPmMask() { return proxyFor.getPmMask(); }
public void setPmMask(int mask) { proxyFor.setPmMask(mask); }
//}}}
//{{{ calcBoundingBox, calcRadiusSq
//##################################################################################################
/**
* Gets a bounding box for the current model.
* @param bound the first 6 elements get set to { minX, minY, minZ, maxX, maxY, maxZ }.
* Should be called with { +inf, +inf, +inf, -inf, -inf, -inf }
*/
public void calcBoundingBox(float[] bound)
{
syncCoords(); // just to be safe
super.calcBoundingBox(bound);
}
/**
* Gets the square of the radius of this model from the specified center.
* @param center an array with the x, y, and z coordinates of the center
* @return the square of the radius of this element, centered at center
*/
public float calcRadiusSq(float[] center)
{
syncCoords(); // just to be safe
return super.calcRadiusSq(center);
}
//}}}
//{{{ signalTransform
//##################################################################################################
public void signalTransform(Engine engine, Transform xform)
{
syncCoords(); // just to be safe
super.signalTransform(engine, xform);
}
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom)
{
syncCoords(); // just to be safe
super.signalTransform(engine, xform, zoom);
}
//}}}
//{{{ paintStandard, isPickedBy
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
//syncCoords(); // just to be safe
super.paintStandard(engine);
}
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{
//syncCoords(); // just to be safe
return super.isPickedBy(xx, yy, radius, objPick);
}
//}}}
//{{{ get/setName, get/setOwner, toString
//##################################################################################################
/** Gets the name of this element */
public String getName() { return proxyFor.getName(); }
/** Sets the name of this element */
public void setName(String nm)
{
if(proxyFor == null) super.setName(nm); // called by constructor
else proxyFor.setName(nm);
}
/** Determines the owner (parent) of this element */
public AGE getOwner() { return proxyFor.getOwner(); }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{
if(proxyFor == null) super.setOwner(owner); // called by constructor
else proxyFor.setOwner(owner);
}
/** Gets the name of this element (same as getName()
*/
public String toString() { return proxyFor.toString(); }
//}}}
//{{{ getKinemage
//##################################################################################################
/** Retrieves the Kinemage object holding this element, or null if none. */
public Kinemage getKinemage() { return proxyFor.getKinemage(); }
//}}}
//{{{ isVisible, isTotallyOn
//##################################################################################################
/** Indicates whether this element will actually be painted (i.e., is it and all its parents on?) */
public boolean isVisible() { return proxyFor.isVisible(); }
/** Returns true iff this element is On, it's owner is On, it's owner's owner is On, and so on */
public boolean isTotallyOn() { return proxyFor.isTotallyOn(); }
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/BondRot.java 0000644 0000000 0000000 00000006420 11531212670 020112 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import king.*;
//import java.awt.*;
//import java.awt.event.*;
//import java.io.*;
//import java.net.*;
//import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.gui.*;
//import driftwood.util.SoftLog;
//}}}
/**
* BondRot
is an object to represent a BondRot for doing bond rotations like in Mage.
*
*
Copyright (C) 2004 Vincent B. Chen. All rights reserved.
*
Begun in June 2004
**/
public class BondRot {
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
int bondRotNum = -1;
ArrayList bondLists = null;
boolean isOpen = false;
String name = null;
double origAng = 0;
double currAng = 0;
HashMap colorMap = null;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public BondRot(int rotNum) {
bondLists = new ArrayList();
bondRotNum = rotNum;
isOpen = true;
colorMap = new HashMap();
}
//}}}
/**
* Constructor
**/
public BondRot(int rotNum, String nm, double angle) {
bondLists = new ArrayList();
bondRotNum = rotNum;
name = nm;
origAng = angle;
currAng = angle;
isOpen = true;
colorMap = new HashMap();
}
//{{{ Methods
//##################################################################################################
//{{{ Add
//##################################################################################################
/**
* Adds a KList to this bondrot.
**/
public void add(KList list) {
bondLists.add(list);
colorMap.put(list, list.getColor());
}
//{{{
public void setOpen(boolean status) {
isOpen = status;
}
public void setColor(KPaint color) {
Iterator iter = bondLists.iterator();
while (iter.hasNext()) {
KList list = (KList) iter.next();
list.setColor(color);
}
}
public void setAxisColor(KPaint color) {
Iterator iter = bondLists.iterator();
KList list = (KList) iter.next();
list.setColor(color);
}
public void setCurrentAngle(double ang) {
currAng = ang;
}
public void restoreOrigColor() {
Iterator iter = bondLists.iterator();
while (iter.hasNext()) {
KList list = (KList) iter.next();
KPaint color = (KPaint) colorMap.get(list);
list.setColor(color);
}
}
public Iterator iterator() {
return bondLists.iterator();
}
public KList getAxisList() {
return (KList) bondLists.get(0);
}
public double getOrigAngle() {
return origAng;
}
public double getCurrentAngle() {
return currAng;
}
public String getName() {
return name;
}
public boolean isOpen() {
return isOpen;
}
public String toString() {
//return ("BondRot " + bondRotNum + ", Contains: " + bondLists.size() + " lists");
return name;
}
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof BondRot)) return false;
BondRot rot = (BondRot) obj;
if (name.equals(rot.getName())) return true;
else return false;
}
public int hashCode() {
return name.hashCode();
}
}
king-2.21.120420/king/1.x_src/king/core/LabelPoint.java 0000644 0000000 0000000 00000006331 11531212670 020575 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
//import java.io.*;
//import java.text.*;
//import java.util.*;
//import javax.swing.*;
//}}}
/**
* LabelPoint
implements a floating label at some point in space.
*
*
Begun on Mon Jun 24 21:09:57 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class LabelPoint extends AbstractPoint // implements ...
{
//{{{ Static fields
public static final int LEFT = 0;
public static final int CENTER = 0x00800000;
public static final int RIGHT = 0x00400000;
public static final int HALIGN_MASK = ~(CENTER | RIGHT);
//}}}
//{{{ Variable definitions
//##################################################################################################
int minx = 0, miny = 0, maxx = 0, maxy = 0;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new data point representing a label.
*
* @param list the list that contains this point
* @param label the pointID of this point
*/
public LabelPoint(KList list, String label)
{
super(list, label);
}
//}}}
//{{{ paintStandard
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine)
{
KPaint maincolor = getDrawingColor(engine);
if(maincolor.isInvisible()) return;
Paint paint = maincolor.getPaint(engine.backgroundMode, engine.colorCue);
int width, ascent, descent;
width = engine.painter.getLabelWidth(this.toString());
ascent = engine.painter.getLabelAscent(this.toString());
descent = engine.painter.getLabelDescent(this.toString());
maxy = (int)y + descent; // screen coords: big y is down
miny = (int)y - ascent; // "
if((multi & CENTER) != 0) { minx = (int)x - width/2; }
else if((multi & RIGHT) != 0) { minx = (int)x - width; }
else { minx = (int)x; }
maxx = minx + width;
engine.painter.paintLabel(paint, this.toString(), minx, y, z);
}
//}}}
//{{{ alignment functions
//##################################################################################################
public void setHorizontalAlignment(int align)
{
multi = (multi & HALIGN_MASK) | align;
}
//}}}
//{{{ isPickedBy()
//##################################################################################################
/** Returns this if the specified pick hits it, else returns null. */
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick)
{
// Labels should always act in "object pick" mode
//if(objPick && minx <= xx && xx <= maxx && miny <= yy && yy <= maxy)
if(minx <= xx && xx <= maxx && miny <= yy && yy <= maxy)
return this;
else
return super.isPickedBy(xx, yy, radius, objPick);
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KinemageSignalSubscriber.java 0000644 0000000 0000000 00000003334 11531212670 023446 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* KinemageSignalSubscriber
allows objects to
* receive signals from a KinemageSignal, which reflects
* state changes in the kinemage.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Thu Mar 27 10:32:24 EST 2003
*/
public interface KinemageSignalSubscriber //extends ... implements ...
{
/**
* The hierarchical, logical structure of the kinemage has changed.
* This includes addition/deletion of groups, subgroups, lists,
* masters, and views (but not points).
* Also included are changes to the animate, 2animate, dominant,
* and nobutton properties.
*/
public static final int STRUCTURE = 1<<0;
/**
* The 3-D visual manifestation of the kinemage has changed.
* This includes addition/deletion of points.
* Also included are rotations, selection of a new viewpoint,
* selection of a new aspect, and changes to point or list display properties.
*/
public static final int APPEARANCE = 1<<1;
/**
* A call to this method indicates that the specified
* kinemage has changed somehow.
*
*
This method will be called in response to KinemageSignal.signalKinemage().
*
* @param kinemage the Kinemage object that has changed
* @param bitmask a set of flags describing which properties have changed.
*/
public void signalKinemage(Kinemage kinemage, int bitmask);
}//class
king-2.21.120420/king/1.x_src/king/core/Aspect.java 0000644 0000000 0000000 00000004100 11531212670 017753 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* Aspect
has not yet been documented.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Wed Dec 4 10:26:15 EST 2002
*/
public class Aspect //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
Kinemage parent;
Integer index;
String name;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
* @param parent the kinemage this aspect belongs to.
* @param name a descriptive name for this aspect.
* @param index the index of this aspect in the aspect string,
* where the first position is index 1.
*/
public Aspect(Kinemage parent, String name, Integer index)
{
this.parent = parent;
this.name = name;
this.index = index;
}
//}}}
//{{{ getName, getIndex
//##################################################################################################
public String getName()
{ return name; }
public Integer getIndex()
{ return index; }
//}}}
//{{{ selectedFromMenu
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void selectedFromMenu(ActionEvent ev)
{
if(parent != null) parent.notifyAspectSelected(this);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/ProxyPoint.java 0000644 0000000 0000000 00000034354 11531212670 020705 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.r3.*;
//}}}
/**
* ProxyPoint
implements all the functions of KPoint by delegating
* them to another KPoint.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Mon Oct 18 09:33:32 EDT 2004
*/
public class ProxyPoint implements KPoint
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
KPoint proxyFor;
//}}}
//{{{ Constructor(s)
//##############################################################################
public ProxyPoint(KPoint proxyFor)
{
super();
this.proxyFor = proxyFor;
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ clone
//##################################################################################################
public Object clone() { return proxyFor.clone(); }
//}}}
//{{{ get/setOrigX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getX(). */
public float getOrigX() { return proxyFor.getOrigX(); }
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getY(). */
public float getOrigY() { return proxyFor.getOrigY(); }
/** Returns the untransformed coordinate for this point.
* @deprecated In favor of getZ). */
public float getOrigZ() { return proxyFor.getOrigZ(); }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setX(). */
public void setOrigX(double xx) { proxyFor.setOrigX(xx); }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setY(). */
public void setOrigY(double yy) { proxyFor.setOrigY(yy); }
/** Assigns a value to the untransformed coordinate for this point.
* @deprecated In favor of setZ(). */
public void setOrigZ(double zz) { proxyFor.setOrigZ(zz); }
/** Assigns a value to the untransformed coordinates for this point.
* @deprecated In favor of setXYZ(). */
public void setOrigXYZ(Tuple3 t) { proxyFor.setOrigXYZ(t); }
//}}}
//{{{ get/setX/Y/Z
//##################################################################################################
/** Returns the untransformed coordinate for this point */
public double getX() { return proxyFor.getX(); }
/** Returns the untransformed coordinate for this point */
public double getY() { return proxyFor.getY(); }
/** Returns the untransformed coordinate for this point */
public double getZ() { return proxyFor.getZ(); }
/** Assigns a value to the untransformed coordinate for this point */
public void setX(double xx) { proxyFor.setX(xx); }
/** Assigns a value to the untransformed coordinate for this point */
public void setY(double yy) { proxyFor.setY(yy); }
/** Assigns a value to the untransformed coordinate for this point */
public void setZ(double zz) { proxyFor.setZ(zz); }
/** Assigns a value to the untransformed coordinates for this point */
public void setXYZ(double xx, double yy, double zz) { proxyFor.setXYZ(xx, yy, zz); }
//}}}
//{{{ get/setDrawX/Y/Z
//##################################################################################################
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawX() { return proxyFor.getDrawX(); }
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawY() { return proxyFor.getDrawY(); }
/** Returns the fully transformed (drawing) coordinate for this point */
public float getDrawZ() { return proxyFor.getDrawZ(); }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawX(double xx) { proxyFor.setDrawX(xx); }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawY(double yy) { proxyFor.setDrawY(yy); }
/** Assigns a value to the fully transformed (drawing) coordinate for this point */
public void setDrawZ(double zz) { proxyFor.setDrawZ(zz); }
/** Assigns a value to the fully transformed (drawing) coordinates for this point */
public void setDrawXYZ(Tuple3 t) { proxyFor.setDrawXYZ(t); }
//}}}
//{{{ get/setAllCoords, useCoordsXYZ
//##################################################################################################
/**
* Stores an array of coordinates for "high-dimensional" points.
* The float[] is stored without cloning and so is subject to overwrite.
*/
public void setAllCoords(float[] coords) { proxyFor.setAllCoords(coords); }
/**
* Retrieves the "high-dimensional" coordinates of this point, or null if not set.
* The float[] is returned without cloning and so is subject to overwrite.
*/
public float[] getAllCoords() { return proxyFor.getAllCoords(); }
/**
* Copies the high-dimensional coordinates at the specified indices
* into this point's (untransformed) X, Y, and Z fields.
* If a index is out of range (0-based), it is ignored and the value is not changed.
*/
public void useCoordsXYZ(int xIndex, int yIndex, int zIndex) { proxyFor.useCoordsXYZ(xIndex, yIndex, zIndex); }
//}}}
//{{{ get/setPrev, isBreak
//##################################################################################################
/**
* Sets the point that precedes this one.
* This matters to "chainable" points, like vectors and triangles.
* For other points, it does nothing.
* @param pt the point preceding this one in seqence
*/
public void setPrev(KPoint pt) { proxyFor.setPrev(pt); }
/**
* Gets the point preceding this one in the chain.
* @return the preceding point, or null if (a) this is a break in the chain or (b) this is not a chainable point type.
*/
public KPoint getPrev() { return proxyFor.getPrev(); }
/**
* True iff this is a chainable point type (e.g. vector, triangle) AND there is a chain break.
*/
public boolean isBreak() { return proxyFor.isBreak(); }
//}}}
//{{{ is/get/set{On, Unpickable, Ghost, Color, Aspects, Width, Radius, Comment}
//##################################################################################################
/** Indicates whether this element will paint itself, given the chance */
public boolean isOn() { return proxyFor.isOn(); }
/** Sets the painting status of this element */
public void setOn(boolean paint) { proxyFor.setOn(paint); }
/** Indicates whether this point can be picked with the mouse */
public boolean isUnpickable() { return proxyFor.isUnpickable(); }
/** Sets the picking status of this point */
public void setUnpickable(boolean b) { proxyFor.setUnpickable(b); }
/** Indicates whether this point is a "ghost" for Mage */
public boolean isGhost() { return proxyFor.isGhost(); }
/** Sets the ghost status of this point */
public void setGhost(boolean b) { proxyFor.setGhost(b); }
/** Returns the color of this point, or null if it inherits from its list */
public KPaint getColor() { return proxyFor.getColor(); }
/** Sets the color of this point. */
public void setColor(KPaint c) { proxyFor.setColor(c); }
/** Gets the aspect string of this point */
public String getAspects() { return proxyFor.getAspects(); }
/** Sets the aspect string of this point */
public void setAspects(String a) { proxyFor.setAspects(a); }
/** Gets the line width of this point, if applicable */
public int getWidth() { return proxyFor.getWidth(); }
/** Sets the line width of this point, if applicable */
public void setWidth(int w) { proxyFor.setWidth(w); }
/** Gets the radius of this point, if applicable */
public float getRadius() { return proxyFor.getRadius(); }
/** Sets the radius of this point, if applicable */
public void setRadius(float radius) { proxyFor.setRadius(radius); }
/** Sets the point comment for this point. */
public void setComment(String cmt) { proxyFor.setComment(cmt); }
/** Gets the comment for this point, which defaults to null. */
public String getComment() { return proxyFor.getComment(); }
//}}}
//{{{ getDrawingColor
//##################################################################################################
/** Returns the color that will be used to draw this point (ignoring aspects). Never null. */
public KPaint getDrawingColor() { return proxyFor.getDrawingColor(); }
/** Returns the color that will be used to draw this point, taking aspects into account. Never null. */
public KPaint getDrawingColor(Engine engine) { return proxyFor.getDrawingColor(engine); }
//}}}
//{{{ pmHit, pmWouldHit, get/setPmMask
//##################################################################################################
/**
* Processes a pointmaster on/off request.
* @param mask the bitmask indicating which masters are being turned on/off
* @param offmask the bitmask indicating which masters are already off
* @param turnon true
if affected points are to be turned on,
* false
if affected points are to be turned off.
*/
public void pmHit(int mask, int offmask, boolean turnon) { proxyFor.pmHit(mask, offmask, turnon); }
/** Indicates whether or not the given pointmaster set would affect this point. */
public boolean pmWouldHit(int mask) { return proxyFor.pmWouldHit(mask); }
public int getPmMask() { return proxyFor.getPmMask(); }
public void setPmMask(int mask) { proxyFor.setPmMask(mask); }
//}}}
//{{{ calcBoundingBox, calcRadiusSq
//##################################################################################################
/**
* Gets a bounding box for the current model.
* @param bound the first 6 elements get set to { minX, minY, minZ, maxX, maxY, maxZ }.
* Should be called with { +inf, +inf, +inf, -inf, -inf, -inf }
*/
public void calcBoundingBox(float[] bound) { proxyFor.calcBoundingBox(bound); }
/**
* Gets the square of the radius of this model from the specified center.
* @param center an array with the x, y, and z coordinates of the center
* @return the square of the radius of this element, centered at center
*/
public float calcRadiusSq(float[] center) { return proxyFor.calcRadiusSq(center); }
//}}}
//{{{ signalTransform
//##################################################################################################
public void signalTransform(Engine engine, Transform xform) { proxyFor.signalTransform(engine, xform); }
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
* @param zoom the zoom factor encoded by the Transform,
* as a convenience for resizing things.
*/
public void signalTransform(Engine engine, Transform xform, double zoom) { proxyFor.signalTransform(engine, xform, zoom); }
//}}}
//{{{ paintStandard, isPickedBy
//##################################################################################################
/**
* Renders this Paintable to the specified graphics surface,
* using the display settings from engine.
*/
public void paintStandard(Engine engine) { proxyFor.paintStandard(engine); }
/**
* Returns true if the specified pick hits this point, else returns false
* Pays no attention to whether this point is marked as unpickable.
* @param radius the desired picking radius
* @param objPick whether we should try to pick solid objects in addition to points
* @return the KPoint that should be counted as being picked, or null for none.
* Usually this
, but maybe not for object picking.
*/
public KPoint isPickedBy(float xx, float yy, float radius, boolean objPick) { return proxyFor.isPickedBy(xx, yy, radius, objPick); }
//}}}
//{{{ get/setName, get/setOwner, toString
//##################################################################################################
/** Gets the name of this element */
public String getName() { return proxyFor.getName(); }
/** Sets the name of this element */
public void setName(String nm) { proxyFor.setName(nm); }
/** Determines the owner (parent) of this element */
public AGE getOwner() { return proxyFor.getOwner(); }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner) { proxyFor.setOwner(owner); }
/** Gets the name of this element (same as getName()
*/
public String toString() { return proxyFor.toString(); }
//}}}
//{{{ getKinemage
//##################################################################################################
/** Retrieves the Kinemage object holding this element, or null if none. */
public Kinemage getKinemage() { return proxyFor.getKinemage(); }
//}}}
//{{{ isVisible, isTotallyOn
//##################################################################################################
/** Indicates whether this element will actually be painted (i.e., is it and all its parents on?) */
public boolean isVisible() { return proxyFor.isVisible(); }
/** Returns true iff this element is On, it's owner is On, it's owner's owner is On, and so on */
public boolean isTotallyOn() { return proxyFor.isTotallyOn(); }
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/MasterGroup.java 0000644 0000000 0000000 00000027273 11531212670 021024 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import driftwood.gui.IndentBox;
//}}}
/**
* MasterGroup
is used to implements masters.
*
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*
Begun on Sun Jun 2 18:54:11 EDT 2002
*/
public class MasterGroup extends AGE // implements ...
{
//{{{ Static fields
//}}}
//{{{ Variable definitions
//##################################################################################################
public int pm_mask = 0; // no point masters to start with
boolean indent = false;
boolean forceOnOff = false; // was state specified in kin? See setOnForced()
Kinemage parent;
//}}}
//{{{ get/setOwner()
//##################################################################################################
/** Determines the owner (parent) of this element */
public AGE getOwner()
{ return parent; }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{
parent = (Kinemage)owner;
}
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new master control.
*
* @param owner the Kinemage that owns this master
* @param label the ID of this master
*/
public MasterGroup(Kinemage owner, String label)
{
children = new ArrayList(10);
setOwner(owner);
setName(label);
}
//}}}
//{{{ cboxHit, setOn{Limited, Forced}, buildButtons
//##################################################################################################
/** Called when the associated checkbox is turned on/off */
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void cboxHit(ActionEvent ev)
{
this.setOn(cbox.getModel().isSelected());
notifyCboxHit();
}
/**
* Turns the checkbox on/off from within the program.
* Automatically makes the same change to all groups immediately under this one.
* Doesn't automatically trigger a redraw.
*/
public void setOn(boolean alive)
{
super.setOn(alive);
touchMaster(alive);
if(pm_mask != 0) pmHit(pm_mask, alive);
}
/**
* Has the effect of setOn(), but without triggering the master.
* That is, all groups/subgroups/lists/points that are under the control
* of this master WILL NOT be affected by this function call.
*/
public void setOnLimited(boolean alive)
{
super.setOn(alive);
}
/**
* Has the effect of setOn(), but delays triggering the master until
* syncState() is called. This is useful for explicit 'on' and 'off'
* designations of masters in the kinemage file.
*/
public void setOnForced(boolean alive)
{
setOnLimited(alive);
this.forceOnOff = true;
}
/** Builds a grouping of Mage-style on/off buttons in the specified container. */
protected void buildButtons(Container cont)
{
if(hasButton())
{
if(indent)
{
IndentBox ibox = new IndentBox(cbox);
ibox.setIndent(8);
cont.add(ibox);
}
else cont.add(cbox);
}
}
//}}}
//{{{ touchMaster, touchAGE
//##################################################################################################
/**
* Traverses the kinemage, realizing the effects of turning on/off a single master.
* @param state true for on, false for off
*/
private void touchMaster(boolean state)
{
if(parent == null) return;
// Build a list of names of masters that are off
ArrayList mastersOff = new ArrayList();
for(Iterator iter = parent.masterList().iterator(); iter.hasNext(); )
{
MasterGroup m = (MasterGroup)iter.next();
if(!m.isOn()) mastersOff.add(m.getName());
}
String[] mOff = (String[])mastersOff.toArray(new String[mastersOff.size()]);
String mName = this.getName();
Iterator grIter, suIter, liIter;
// Traverse the hierarchy applying the master
for(grIter = parent.iterator(); grIter.hasNext(); )
{
KGroup group = (KGroup)grIter.next();
touchAGE(group, state, mName, mOff);
for(suIter = group.iterator(); suIter.hasNext(); )
{
KSubgroup subgroup = (KSubgroup)suIter.next();
touchAGE(subgroup, state, mName, mOff);
for(liIter = subgroup.iterator(); liIter.hasNext(); )
{
KList list = (KList)liIter.next();
touchAGE(list, state, mName, mOff);
}//lists
}//subgroups
}//groups
}
/**
* Makes a master take affect on a single AGE.
* If state is false (off), the AGE is turned off.
* If state is true (on), *and* the AGE isn't controlled by a master that's off, it's turned on.
* @param mName the master adopting the state 'state'
* @param mOff all other masters that are already off
*/
private void touchAGE(AGE age, boolean state, String mName, String[] mOff)
{
if(age.hasMaster(mName) && age.isOn() != state)
{
// master was just turned on and age is off
if(state)
{
for(int i = 0; i < mOff.length; i++)
if(age.hasMaster(mOff[i])) return;
age.setOn(true);
}
// master was just turned off and age is on
else age.setOn(false);
}
}
//}}}
//{{{ syncState
//##################################################################################################
/**
* Traverses the kinemage, examining the states of its targets.
* If the master is on, it will be turned off iff none of its targets are on.
* If the master is off, all targets will be turned off.
* Assume that pointmastered points will be on.
*/
public void syncState()
{
if(parent == null) return;
if(this.forceOnOff)
{
// This *WILL* trigger the master to turn things it controls ON or OFF
this.setOn( this.isOn() );
//this.forceOnOff = false;
}
else if(this.isOn())
{
Iterator grIter, suIter, liIter, ptIter;
KGroup group;
KSubgroup subgroup;
KList list;
KPoint point;
String masterName = this.getName();
boolean state = false;
for(grIter = parent.iterator(); !state && grIter.hasNext(); )
{
group = (KGroup)grIter.next();
if(group.hasMaster(masterName)) state = state || group.isOn();
for(suIter = group.iterator(); !state && suIter.hasNext(); )
{
subgroup = (KSubgroup)suIter.next();
if(subgroup.hasMaster(masterName)) state = state || subgroup.isOn();
for(liIter = subgroup.iterator(); !state && liIter.hasNext(); )
{
list = (KList)liIter.next();
if(list.hasMaster(masterName)) state = state || list.isOn();
if(pm_mask != 0) // only do this if we're a pointmaster
{
for(ptIter = list.iterator(); !state && ptIter.hasNext(); )
{
point = (KPoint)ptIter.next();
state = state || point.pmWouldHit(pm_mask);
}//points
}//if pointmaster
}//lists
}//subgroups
}//groups
// This won't trigger the master to turn on groups that are off
this.setOnLimited(state);
}//if this master was on to start with...
else
{
// Master wasn't on, but wasn't forced (ie wasn't explicitly specified in the kin).
// This should never happen, but if it did no action would be needed.
}
}
//}}}
//{{{ setPmMask, pmHit
//##################################################################################################
/** Sets the point master flags of this button based on a string */
public void setPmMask(String mask)
{
if(parent != null)
pm_mask = parent.toPmBitmask(mask, true, false);
// assume that if we have points, at least some of them are on
// therefore, this master should start out on, too
///super.setOn(true);
}
/**
* Processes a pointmaster on/off request.
* @param mask the bitmask indicating which masters are being turned on/off
* @param turnon true
if affected groups are to be turned on,
* false
if affected groups are to be turned off.
*/
public void pmHit(int mask, boolean turnon)
{
if(parent == null) return;
// Build a mask of master bits that are off; we're already on
int offmask = 0;
for(Iterator iter = parent.masterList().iterator(); iter.hasNext(); )
{
MasterGroup m = (MasterGroup)iter.next();
if(!m.isOn()) offmask |= m.pm_mask;
}
if(turnon && (mask & ~offmask) == 0) return;
//System.err.println(" turnon = "+turnon);
//System.err.println(" mask = "+Integer.toBinaryString(mask));
//System.err.println("offmask = "+Integer.toBinaryString(offmask));
Iterator grIter, suIter, liIter, ptIter;
KGroup group;
KSubgroup subgroup;
KList list;
KPoint point;
for(grIter = parent.iterator(); grIter.hasNext(); )
{
group = (KGroup)grIter.next();
for(suIter = group.iterator(); suIter.hasNext(); )
{
subgroup = (KSubgroup)suIter.next();
for(liIter = subgroup.iterator(); liIter.hasNext(); )
{
list = (KList)liIter.next();
for(ptIter = list.iterator(); ptIter.hasNext(); )
{
point = (KPoint)ptIter.next();
point.pmHit(mask, offmask, turnon);
}//points
}//lists
}//subgroups
}//groups
}//pmHit()
//}}}
//{{{ MutableTreeNode functions
//##################################################################################################
public void insert(MutableTreeNode child, int index)
{
throw new UnsupportedOperationException("Masters can't be manipulated as part of the tree!");
}
//}}}
//{{{ addMaster, removeMaster, hasMaster, masterIterator
//##################################################################################################
/** Not supported */
public void addMaster(String masterName)
{ throw new UnsupportedOperationException("Not supported by MasterGroup"); }
/** Not supported */
public void removeMaster(String masterName)
{ throw new UnsupportedOperationException("Not supported by MasterGroup"); }
/** Not supported */
public boolean hasMaster(String masterName)
{ throw new UnsupportedOperationException("Not supported by MasterGroup"); }
/** Not supported */
public Iterator masterIterator()
{ throw new UnsupportedOperationException("Not supported by MasterGroup"); }
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/AHE.java 0000644 0000000 0000000 00000003772 11531212670 017147 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* AHE
(Abstract Hierarchy Element) is the basis for all points, lists, groups, etc.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 10:50:32 EDT 2002
*/
public interface AHE extends TransformSignalSubscriber
{
/** Gets the name of this element */
public String getName();
/** Sets the name of this element */
public void setName(String nm);
/** Determines the owner (parent) of this element */
public AGE getOwner();
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner);
/** Retrieves the Kinemage object holding this element, or null if none. */
public Kinemage getKinemage();
/** Indicates whether this element will paint itself, given the chance */
public boolean isOn();
/** Sets the painting status of this element */
public void setOn(boolean paint);
/** Indicates whether this element will actually be painted (i.e., is it and all its parents on?) */
public boolean isVisible();
/** Returns true iff this element is On, it's owner is On, it's owner's owner is On, and so on */
public boolean isTotallyOn();
/**
* Gets a bounding box for the current model.
* @param bound the first 6 elements get set to { minX, minY, minZ, maxX, maxY, maxZ }.
* Should be called with { +inf, +inf, +inf, -inf, -inf, -inf }
*/
public void calcBoundingBox(float[] bound);
/**
* Gets the square of the radius of this model from the specified center.
* @param center an array with the x, y, and z coordinates of the center
* @return the square of the radius of this element, centered at center
*/
public float calcRadiusSq(float[] center);
}//class
king-2.21.120420/king/1.x_src/king/core/KGroup.java 0000644 0000000 0000000 00000011637 11531212670 017760 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.core;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.tree.*;
import driftwood.gui.*;
//}}}
/**
* KGroup
is the KiNG implementation of a Mage group.
*
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*
Begun on Wed Oct 2 12:10:01 EDT 2002
*/
public class KGroup extends AGE implements Cloneable
{
//{{{ Variable definitions
//##################################################################################################
Kinemage parent = null;
boolean animate = false;
boolean animate2 = false;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/** Constructor */
public KGroup()
{
children = new ArrayList(10);
setName(null);
}
/** Constructor */
public KGroup(Kinemage owner, String nm)
{
children = new ArrayList(10);
setOwner(owner);
setName(nm);
}
//}}}
//{{{ clone
//##################################################################################################
/**
* Creates a copy of this group and all its children.
* @param clonePoints whether to clone even the individual points,
* or whether we should use instance= at the list level instead.
*/
public Object clone(boolean clonePoints)
{
try
{
KGroup x = (KGroup) super.clone(clonePoints);
x.setName( x.getName() ); // tricks it into creating a new JCheckBox object
// Deep copy of children
x.children = new ArrayList();
for(Iterator iter = this.children.iterator(); iter.hasNext(); )
{
KSubgroup child = (KSubgroup) iter.next();
KSubgroup clone = (KSubgroup) child.clone(clonePoints);
clone.setOwner(x);
x.add(clone);
}
// Semi-deep copy of masters, which just contains Strings
if(this.masters != null) x.masters = new ArrayList(this.masters);
return x;
}
catch(CloneNotSupportedException ex)
{ throw new Error("Clone failed in cloneable object"); }
}
//}}}
//{{{ setName()
//##################################################################################################
/** Sets the name of this element */
public void setName(String nm)
{
super.setName(nm);
StringBuffer buttonName = new StringBuffer();
if(this.isAnimate()) buttonName.append("*");
if(this.is2Animate()) buttonName.append("%");
if(this.isAnimate() || this.is2Animate()) buttonName.append(" ");
buttonName.append(nm);
cbox.setText(buttonName.toString());
}
//}}}
//{{{ get/setOwner()
//##################################################################################################
/** Determines the owner (parent) of this element */
public AGE getOwner()
{ return parent; }
/** Establishes the owner (parent) of this element */
public void setOwner(AGE owner)
{
parent = (Kinemage)owner;
}
//}}}
//{{{ is/set(2)Animate()
//##################################################################################################
/** Checks to see if this group should be animated. */
public boolean isAnimate() { return animate; }
/** Sets the animate property. Animations still must be regenerated manually! */
public void setAnimate(boolean b) { animate = b; setName(getName()); }
/** Checks to see if this group should be animated. */
public boolean is2Animate() { return animate2; }
/** Sets the animate property. Animations still must be regenerated manually! */
public void set2Animate(boolean b) { animate2 = b; setName(getName()); }
//}}}
//{{{ add()
//##################################################################################################
/** Adds a child to this element */
public void add(KSubgroup child)
{ children.add(child); }
//}}}
//{{{ MutableTreeNode functions -- insert()
//##################################################################################################
public void insert(MutableTreeNode child, int index)
{
if(! (child instanceof KSubgroup)) throw new IllegalArgumentException("Groups can only contain subgroups!");
if(index < 0 || index > children.size()) children.add(child);
else children.add(index, child);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/core/KingView.java 0000644 0000000 0000000 00000037306 11531212670 020275 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
package king.core;
import java.awt.event.*;
import java.io.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* KingView
holds a rotation matrix that specifies the current view or some saved view.
* Views are thread-safe, although most King components are not.
* This allows e.g. an auto-rocker to update the view in the background even if the event thread is repainting the window.
*
*
Zooms and clipping are specified such that a zoom factor of 1.0 means the object will fill the available
* display space without extending outside it, regardless of its orientation.
* A clipping value of 1.0 means that at a zoom of 1.0, no part of the object will be clipped.
*
*
Note that changing the rotation, zoom, etc. does NOT trigger a repaint of the graphics window --
* that is the responsibility of the caller.
*
*
Begun on Thu May 23 21:08:29 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class KingView
{
//{{{ Static fields
static final int N_UPDATES_ALLOWED = 100;
//}}}
//{{{ Variable definitions
//##################################################################################################
Kinemage parent = null;
// The label used on the View menu
String ID = "Unnamed view";
// The rotation matrix
public float[][] xform = { {1f, 0f, 0f}, {0f, 1f, 0f}, {0f, 0f, 1f} };
// Coordinates (in real-space) of the center of rotation
float[] center = null;
/** The zooming factor */
float zoom = 0f;
/** The span factor, an alternate representation of zoom. */
float span = 0f;
/** The clipping factor */
float clip = 1f;
/** The elements of the transformation matrix, in real-space. Call compile() before using them! */
public float R11 = 1f, R12 = 0f, R13 = 0f, R21 = 0f, R22 = 1f, R23 = 0f, R31 = 0f, R32 = 0f, R33 = 1f;
/** The center of rotation, in real-space. Call compile() before using them! */
public float cx = 0f, cy = 0f, cz = 0f;
/** 0-based indices of which viewing axes to use when this view is activated. */
int[] viewingAxes = null; // null -> don't change axes when selected
// A counter for when this matrix needs to be 'cleaned'
int nUpdates = 0;
//}}}
//{{{ Constructors & clone()
//##################################################################################################
/**
* Constructor
*/
public KingView(Kinemage kin)
{
parent = kin;
}
/** Duplicates this object */
public synchronized Object clone()
{
KingView ret = new KingView(parent);
ret.ID = ID;
ret.xform = (float[][])xform.clone();
if(center == null) ret.center = getCenter();
else ret.center = (float[])center.clone();
ret.zoom = zoom;
ret.span = span;
ret.clip = clip;
ret.compile();
return ret;
}
//}}}
//{{{ get/setName(), toString()
//##################################################################################################
/** Gets the name of this element */
public String getName()
{ return ID; }
/** Sets the name of this element */
public synchronized void setName(String nm)
{ ID = nm; }
/** Gets the name of this element (same as getName()
*/
public String toString()
{ return getName(); }
//}}}
//{{{ Matrix math routines
//##################################################################################################
// Multiplies two 3x3 matrices
float[][] mmult(float[][] A, float[][] B)
{
float[][] R = new float[3][3];
int i, j, k;
float r;
for(i = 0; i < 3; i++)
{// row loop
for(j = 0; j < 3; j++)
{// column loop
r = 0f;
// index loop
for(k = 0; k < 3; k++) r += A[i][k] * B[k][j];
R[i][j] = r;
}// column loop
}// row loop
return R;
}
// Multiplies a 3x3 matrix with a 3x1 vector
float[] mmult(float[][] A, float[] X)
{
float[] R = new float[3];
int i, j;
float r;
for(i = 0; i < 3; i++)
{// row loop
r = 0f;
// index loop
for(j = 0; j < 3; j++) r += A[i][j] * X[j];
R[i] = r;
}
return R;
}
/**
* Adjusts matrix values for self-consistency -- http://www.makegames.com/3drotation/
*
* R is special orthogonal (I'll trust their math):
* R R' = I (R times its transpose is identity)
* det R = 1 (determinant of R equals 1)
*
* "A more helpful set of properties is provided by Michael E. Pique in Graphics Gems (Glassner, Academic Press, 1990):
* 1. R is normalized: the squares of the elements in any row or column sum to 1.
* 2. R is orthogonal: the dot product of any pair of rows or any pair of columns is 0.
* 3. The rows of R represent the coordinates in the original space of unit vectors along the coordinate axes of the rotated space. (Figure 1).
* 4. The columns of R represent the coordinates in the rotated space of unit vectors along the axes of the original space."
*
* Here I follow the procedure described above for building a "good" rotation matrix (sort of),
* but without using what they call a World Up vector, since we're in a molecule & that doesn't mean anything.
* I call the rows X*, Y*, and Z*, as per (3) above
*/
void normalize(float[][] A)
{
float mag;
// Don't change 3rd row (Z*) except to normalize it (magnitude --> 1)
mag = (float)Math.sqrt(A[2][0]*A[2][0] + A[2][1]*A[2][1] + A[2][2]*A[2][2]);
A[2][0] = A[2][0]/mag; A[2][1] = A[2][1]/mag; A[2][2] = A[2][2]/mag;
// Normalize 2nd row (Y*), then take cross product to get the first ( Y* x Z* = X* )
// X* will be normalized b/c Y* and Z* are.
// x =
mag = (float)Math.sqrt(A[1][0]*A[1][0] + A[1][1]*A[1][1] + A[1][2]*A[1][2]);
A[1][0] = A[1][0]/mag; A[1][1] = A[1][1]/mag; A[1][2] = A[1][2]/mag;
A[0][0] = A[1][1]*A[2][2] - A[1][2]*A[2][1];
A[0][1] = A[1][2]*A[2][0] - A[1][0]*A[2][2];
A[0][2] = A[1][0]*A[2][1] - A[1][1]*A[2][0];
// Now let Y* = Z* x X* so it's perpendicular to both!
// x =
A[1][0] = A[2][1]*A[0][2] - A[2][2]*A[0][1];
A[1][1] = A[2][2]*A[0][0] - A[2][0]*A[0][2];
A[1][2] = A[2][0]*A[0][1] - A[2][1]*A[0][0];
}
// Constructs the transpose of a 3x3 matrix
float[][] transpose(float[][] A)
{
float[][] R = new float[3][3];
int i, j;
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++) R[i][j] = A[j][i];
}
return R;
}
//}}} Matrix math routines
//{{{ Compositing (compile())
//##################################################################################################
/**
* Updates this view's public fields to reflect the current internal state.
*/
public synchronized void compile()
{
R11 = xform[0][0];// * zoom;
R12 = xform[0][1];// * zoom;
R13 = xform[0][2];// * zoom;
R21 = xform[1][0];// * zoom;
R22 = xform[1][1];// * zoom;
R23 = xform[1][2];// * zoom;
R31 = xform[2][0];// * zoom;
R32 = xform[2][1];// * zoom;
R33 = xform[2][2];// * zoom;
if(center == null) getCenter();
cx = center[0]; cy = center[1]; cz = center[2];
}
//}}}
//{{{ Rotation functions
//##################################################################################################
/**
* Rotates about the axis defined as 'x' by the basis of this tranform.
* @param t the amount of rotation, in radians
*/
public synchronized void rotateX(float t)
{
float sin, cos;
sin = (float)Math.sin(t);
cos = (float)Math.cos(t);
float[][] rot = { {1f, 0f, 0f}, {0f, cos, -sin}, {0f, sin, cos} };
xform = mmult(rot, xform);
if(++nUpdates % N_UPDATES_ALLOWED == 0) { nUpdates = 0; normalize(xform); }
}
/**
* Rotates about the axis defined as 'y' by the basis of this tranform.
* @param t the amount of rotation, in radians
*/
public synchronized void rotateY(float t)
{
float sin, cos;
sin = (float)Math.sin(t);
cos = (float)Math.cos(t);
float[][] rot = { {cos, 0f, sin}, {0f, 1f, 0f}, {-sin, 0f, cos} };
xform = mmult(rot, xform);
if(++nUpdates % N_UPDATES_ALLOWED == 0) { nUpdates = 0; normalize(xform); }
}
/**
* Rotates about the axis defined as 'z' by the basis of this tranform.
* @param t the amount of rotation, in radians
*/
public synchronized void rotateZ(float t)
{
float sin, cos;
sin = (float)Math.sin(t);
cos = (float)Math.cos(t);
float[][] rot = { {cos, -sin, 0f}, {sin, cos, 0f}, {0f, 0f, 1f} };
xform = mmult(rot, xform);
if(++nUpdates % N_UPDATES_ALLOWED == 0) { nUpdates = 0; normalize(xform); }
}
//}}}
//{{{ get/set/adjust functions
//##################################################################################################
/**
* Sets the label used to identify this view.
* Identical to setName()
.
* @param name the name of this view
*/
public synchronized void setID(String name) { setName(name); }
/**
* Sets the matrix used by this view
* @param matrix a 3x3 matrix, matrix[row][col]
*/
public synchronized void setMatrix(float[][] matrix) { xform = (float[][])matrix.clone(); }
/**
* Sets the current zoom factor.
* The zoom factor is defined as the ratio of the span of the kinemage
* to the span of this view, such that values less than 1 appear to be
* distant, and values greater than 1 appear to be zoomed in.
*
* Calling this function will overwrite the previous value for span.
*
* @param z the desired zoom
*/
public synchronized void setZoom(float z) { zoom = z; span = 0f; }
/**
* Gets the span of this view,
* i.e., the desired width of the graphics area in model units.
*/
public float getSpan()
{
if(span <= 0f)
{
if(zoom <= 0f) zoom = 1.0f;
span = parent.getSpan() / zoom;
}
return span;
}
/**
* Set the span of this view, which (if no zoom has been set or zoom is <= 0)
* will set the zoom such that an object s units across fits on screen.
*/
public synchronized void setSpan(float s) { span = s; }
/**
* Returns the current clip factor.
* @return the current clip
*/
public float getClip() { return clip; }
/**
* Sets the current clip factor.
* @param c the desired clip
*/
public synchronized void setClip(float c) { clip = c; }
/** Returns the coordinates of the current center as a float[] = {x,y,z} */
public synchronized float[] getCenter()
{
if(center == null)
{
if(parent != null) center = parent.getCenter();
else
{
float[] dummy = { 0f, 0f, 0f };
center = dummy;
}
}
return (float[])center.clone();
}
/**
* Set the center point for this transform.
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
*/
public synchronized void setCenter(float x, float y, float z)
{
if(center == null) center = new float[3];
center[0] = x;
center[1] = y;
center[2] = z;
}
/**
* Given a pixel offset in rotated and scaled coordinates, calculate an offset in "real" coordinates.
* If x and y are taken from screen coordinates, remember to invert y!
*/
public synchronized float[] translateRotated(int x, int y, int z, int screenSize)
{
float cx, cy, cz, correctedZoom;
correctedZoom = (float)screenSize / getSpan(); //getZoom() * (float)screenSize / parent.getSpan();
cx = (float)x / correctedZoom;
cy = (float)y / correctedZoom;
cz = (float)z / correctedZoom;
float[] tcoord = { cx, cy, cz };
float[] coord = mmult(transpose(xform), tcoord);
return coord;
}
/**
* Given a pixel offset in rotated and scaled coordinates, calculate a new center point.
* If x and y are taken from screen coordinates, remember to invert y!
*/
public synchronized void viewTranslateRotated(int x, int y, int z, int screenSize)
{
float[] coord = translateRotated(x, y, z, screenSize);
float[] orig = getCenter();
setCenter(orig[0]-coord[0], orig[1]-coord[1], orig[2]-coord[2]);
}
//}}}
//{{{ selectedFromMenu, get/setViewingAxes
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void selectedFromMenu(ActionEvent ev)
{
if(parent != null)
{
parent.notifyViewSelected(this);
if(viewingAxes != null)
setAxes(parent, viewingAxes[0], viewingAxes[1], viewingAxes[2]);
}
}
/**
* Stores a set of 0-based indices for the coordinates axes that should be
* placed into X, Y, Z when this view is activated.
* Indices are stored as an int[3], or null (meaning no change).
* This does NOT automatically update the coordinates in the kinemage,
* even if called on the currently active view.
* Coordinates ARE automatically updated when this view is next chosen from the menu.
*/
public void setViewingAxes(int[] indices)
{
if(indices == null) this.viewingAxes = null;
else this.viewingAxes = (int[]) indices.clone();
}
/** Returns the value set by setViewingAxes() (may be null) */
public int[] getViewingAxes() { return this.viewingAxes; }
//}}}
//{{{ setAxes
//##############################################################################
/**
* Copies the high-dimensional coordinates at the specified indices
* into all point's (untransformed) X, Y, and Z fields.
* If a index is out of range (0-based), it is ignored and the value is not changed.
*/
static public void setAxes(Kinemage kin, int xIndex, int yIndex, int zIndex)
{
for(Iterator gi = kin.iterator(); gi.hasNext(); )
{
KGroup group = (KGroup) gi.next();
for(Iterator si = group.iterator(); si.hasNext(); )
{
KSubgroup subgroup = (KSubgroup) si.next();
for(Iterator li = subgroup.iterator(); li.hasNext(); )
{
KList list = (KList) li.next();
// We will miss points with extra coordinates if
// list.dimension wasn't set...
if(list.getDimension() <= 3) continue;
for(Iterator pi = list.iterator(); pi.hasNext(); )
{
KPoint pt = (KPoint) pi.next();
pt.useCoordsXYZ(xIndex, yIndex, zIndex);
}
}
}
}
kin.getCurrentView().setViewingAxes(new int[] {xIndex, yIndex, zIndex});
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/Plugin.java 0000644 0000000 0000000 00000013421 11531212674 017054 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
//import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.gui.*;
import driftwood.util.SoftLog;
//}}}
/**
* Plugin
is a way for arbitrary, specialized
* functionalities to be incorporated into KiNG in a
* highly modular manner.
*
* To be a Plugin, a class should at a minimum implement getToolsMenuItem(),
* getHelpMenuItem(), and toString().
* It's often easier to implement getHelpAnchor() than getHelpMenuItem().
* More complicated plugins should implement getDependencies() and isAppletSafe().
*
* Plugins are very similar to Tools, except that Plugins
* do not receive mouse events from the graphics window; and
* Plugins are not exclusive, whereas activating one Tool
* necessarily de-activates the previous one.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Tue Apr 1 12:23:40 EST 2003
*/
abstract public class Plugin //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
// These are protected so that the Plugin can be subclassed
// outside of the "king" package.
protected ToolBox parent;
protected KingMain kMain;
protected KinCanvas kCanvas;
protected ToolServices services;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public Plugin(ToolBox tb)
{
parent = tb;
kMain = tb.kMain;
kCanvas = tb.kCanvas;
services = tb.services;
}
//}}}
//{{{ getToolsMenuItem, getHelpMenuItem
//##################################################################################################
/**
* Creates a new JMenuItem to be displayed in the Tools menu,
* which will allow the user to access function(s) associated
* with this Plugin.
*
* Only one JMenuItem may be returned, but it could be a JMenu
* that contained several functionalities under it.
*
* The Plugin may return null to indicate that it has no
* associated menu item.
*/
abstract public JMenuItem getToolsMenuItem();
/**
* Creates a new JMenuItem to be displayed in the Help menu,
* which will allow the user to access help information associated
* with this Plugin.
*
* Only one JMenuItem may be returned, but it could be a JMenu
* that contained several items under it. However,
* Plugins are encouraged to consolidate all documentation
* into one location. The king.HTMLHelp class may be of use here.
*
* By default, a menu item will be created that signals the onHelp()
* function, which in turn displays the HTML page named by getHelpURL().
*
* The Plugin may return null to indicate that it has no
* associated menu item.
*/
public JMenuItem getHelpMenuItem()
{
return new JMenuItem(new ReflectiveAction(this.toString(), null, this, "onHelp"));
}
//}}}
//{{{ onHelp, getHelpURL, getHelpAnchor
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelp(ActionEvent ev)
{
URL start = this.getHelpURL();
if(start != null) new HTMLHelp(kMain, start).show();
else JOptionPane.showMessageDialog(kMain.getTopWindow(), "Unable to find documentation for this plugin.", "Sorry!", JOptionPane.ERROR_MESSAGE);
}
/** Returns the URL of a web page explaining use of this tool */
public URL getHelpURL()
{
URL url = getClass().getResource("/king/html/king-manual.html");
String anchor = getHelpAnchor();
if(url != null && anchor != null)
{
try { url = new URL(url, anchor); }
catch(MalformedURLException ex) { ex.printStackTrace(SoftLog.err); }
return url;
}
else return null;
}
/**
* Returns an anchor marking a place within king-manual.html
* that is the help for this plugin. This is called by the default
* implementation of getHelpURL()
.
* If you override that function, you can safely ignore this one.
* @return for example, "#edmap-plugin" (or null)
*/
public String getHelpAnchor()
{ return null; }
//}}}
//{{{ getDependencies, isAppletSafe
//##################################################################################################
/**
* Returns a Collection<String> of all Plugins that must be instantiated
* before this one is. If one or more dependencies cannot be resolved,
* the plugin will generally not be loaded;
* thus, be careful to avoid circular dependencies.
* @return a Collection of the fully-qualified names of all plugins that
* this Plugin depends on, as Strings. The default is no dependencies.
*/
static public Collection getDependencies()
{
return Collections.EMPTY_LIST;
}
/**
* Returns true if and only if this plugin is safe to instantiate when
* KiNG is running as an applet in a web browser.
* Plugins that access the file system or arbitrary URLs (among other things)
* should override this method to return true.
* @return the default value of false
*/
static public boolean isAppletSafe()
{
return true;
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/ToolBoxMW.java 0000644 0000000 0000000 00000003356 11531212674 017456 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//}}}
/**
* ToolBoxMW
extends ToolBox with mouse-wheel functionality.
* This class needs Java 1.4 or later, it is NOT compatible with Java 1.3.
* It should never be referenced directly from anywhere in the KiNG program;
* only references generated through the Reflection API are safe.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Mon Dec 9 10:35:21 EST 2002
*/
public class ToolBoxMW extends ToolBox implements MouseWheelListener
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public ToolBoxMW(KingMain kmain, KinCanvas kcanv)
{
super(kmain, kcanv);
}
//}}}
//{{{ listenTo
//##################################################################################################
/** Does all the work to make the ToolBox listen to the specified component. */
public void listenTo(Component c)
{
super.listenTo(c);
c.addMouseWheelListener(this);
}
//}}}
//{{{ mouseWheelMoved
//##################################################################################################
public void mouseWheelMoved(MouseWheelEvent ev)
{
this.mouseWheelMoved(ev, ev.getWheelRotation());
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/BasicTool.java 0000644 0000000 0000000 00000042727 11531212674 017510 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import driftwood.gui.*;
import driftwood.r3.*;
import driftwood.util.SoftLog;
//}}}
/**
* BasicTool
implements the most common manipulation functions.
* It is intended to serve as a basis for the construction of new tools, which should override
* one or more of the xx_click(), xx_drag(), and xx_wheel() functions.
* Note that some of these functions have default activities;
* descendents may want to replace one or more with null functions.
*
*
Begun on Fri Jun 21 09:30:40 EDT 2002
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*/
public class BasicTool extends Plugin implements MouseListener, MouseMotionListener, TransformSignalSubscriber, WindowListener
{
//{{{ Static fields
static final Object MODE_UNDECIDED = new Object();
static final Object MODE_VERTICAL = new Object();
static final Object MODE_HORIZONTAL = new Object();
//}}}
//{{{ Variable definitions
//##################################################################################################
protected int lastXCoord = 0, lastYCoord = 0;
protected int pressXCoord = 0, pressYCoord = 0;
protected boolean isNearTop = false, isNearBottom = false;
protected Object mouseDragMode = MODE_UNDECIDED;
protected JDialog dialog = null;
private boolean hasBeenCentered = false;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Constructor
*/
public BasicTool(ToolBox tb)
{
super(tb);
}
//}}}
//{{{ start/stop/reset functions
//##################################################################################################
public void start()
{
show();
}
public void stop()
{
hide();
}
public void reset()
{}
//}}}
//{{{ initDialog, show, hide
//##################################################################################################
protected void initDialog()
{
Container content = this.getToolPanel();
if(content == null) return;
dialog = new JDialog(kMain.getTopWindow(), this.toString(), false); // false => not modal
//dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(this); // to make the window close button work
dialog.setContentPane(content);
//dialog.invalidate();
//dialog.validate();
dialog.pack();
}
protected void show()
{
if(dialog == null) initDialog();
if(dialog == null) return;
if(!dialog.isVisible())
{
dialog.pack();
Container w = kMain.getContentContainer();
if(w != null)
{
Point p = w.getLocation();
Dimension dimDlg = dialog.getSize();
Dimension dimWin = w.getSize();
p.x += dimWin.width - (dimDlg.width / 2) ;
p.y += (dimWin.height - dimDlg.height) / 2;
dialog.setLocation(p);
}
dialog.setVisible(true);
}
else
{
dialog.toFront();
}
}
protected void hide()
{
if(dialog != null) dialog.setVisible(false);
}
//}}}
//{{{ xx_click() functions
//##################################################################################################
/** Override this function for (left-button) clicks */
public void click(int x, int y, KPoint p, MouseEvent ev)
{
services.pick(p);
if(p != null && p.getComment() != null)
clickActionHandler(p.getComment());
}
/** Override this function for right-button/shift clicks */
public void s_click(int x, int y, KPoint p, MouseEvent ev)
{
services.centerOnPoint(p);
}
/** Override this function for middle-button/control clicks */
public void c_click(int x, int y, KPoint p, MouseEvent ev)
{ click(x, y, p, ev); }
/** Override this function for shift-control clicks */
public void sc_click(int x, int y, KPoint p, MouseEvent ev)
{ click(x, y, p, ev); }
//}}}
//{{{ xx_drag() functions
//##################################################################################################
/** Override this function for (left-button) drags */
public void drag(int dx, int dy, MouseEvent ev)
{
if(services.doFlatland.isSelected())
{
if(isNearTop) services.ztranslate(dx);
else services.translate(dx, dy);
}
else
{
if(isNearTop) services.pinwheel(dx);
else services.rotate(dx, dy);
}
}
/** Override this function for right-button/shift drags */
public void s_drag(int dx, int dy, MouseEvent ev)
{
if(mouseDragMode == MODE_VERTICAL) services.adjustZoom(dy);
else if(mouseDragMode == MODE_HORIZONTAL) services.adjustClipping(dx);
}
/** Override this function for middle-button/control drags */
public void c_drag(int dx, int dy, MouseEvent ev)
{
if(isNearTop) services.ztranslate(dx);
else services.translate(dx, dy);
}
/** Override this function for shift-control drags */
public void sc_drag(int dx, int dy, MouseEvent ev)
{
// Like normal rotation, but can only rotate about Y axis
if(isNearTop) services.pinwheel(dx);
else services.rotate(dx, 0);
}
//}}}
//{{{ xx_wheel() functions
//##################################################################################################
/** Override this function for mouse wheel motion */
public void wheel(int rotation, MouseEvent ev)
{
services.adjustZoom(rotation*18f);
}
/** Override this function for mouse wheel motion with shift down */
public void s_wheel(int rotation, MouseEvent ev)
{
services.adjustClipping(-rotation*18f);
}
/** Override this function for mouse wheel motion with control down */
public void c_wheel(int rotation, MouseEvent ev)
{ wheel(rotation, ev); }
/** Override this function for mouse wheel motion with shift AND control down */
public void sc_wheel(int rotation, MouseEvent ev)
{ s_wheel(rotation, ev); }
//}}}
//{{{ clickActionHandler
//##################################################################################################
/**
* This function gets called by BasicTool.click() iff the currently selected
* point has a point comment associated with it. Subclasses that wish to
* implement custom actions (which match /^[a-zA-Z]+:.+/
)
* stored in point comments can override this method.
* @param comment the point comment for the picked point
* @return true if the action was handled, false if not
* @since 1.34
*/
protected boolean clickActionHandler(String comment)
{
if(comment.startsWith("http:"))
{
try
{
URL url;
// Saying "http:foo/bar.html" allows us to use relative URLs in applets
if(!comment.startsWith("http://") && kMain.getApplet() != null)
url = new URL(kMain.getApplet().getDocumentBase(), comment.substring(5));
else url = new URL(comment);
new HTMLHelp(kMain, url).show();
return true;
}
catch(MalformedURLException ex)
{
SoftLog.err.println("Bad HTTP URL in point comment: "+comment);
return false;
}
}
else return false;
}
//}}}
//{{{ Mouse motion listeners
//##################################################################################################
/**
* This function is compatible with Java 1.3, so
* we can define keyboard equivalents, etc.
*/
public void mouseWheelMoved(MouseEvent ev, int rotation)
{
boolean isShift, isCtrl;
isShift = ev.isShiftDown();
isCtrl = ev.isControlDown();
if(isShift && isCtrl) sc_wheel(rotation, ev);
else if(isCtrl) c_wheel(rotation, ev);
else if(isShift) s_wheel(rotation, ev);
else wheel(rotation, ev);
}
public void mouseDragged(MouseEvent ev)
{
Dimension dim = kCanvas.getCanvasSize();
Point where = ev.getPoint();
int dx, dy;
dx = where.x - lastXCoord;
dy = where.y - lastYCoord;
// Force a (strong?) committment to either horizonal
// or vertical motion before we take action
/*if(mouseDragMode == MODE_UNDECIDED)
{
if(Math.abs(dy) > 0+Math.abs(dx)) mouseDragMode = MODE_VERTICAL;
else if(Math.abs(dx) > 0+Math.abs(dy)) mouseDragMode = MODE_HORIZONTAL;
}*/
if(mouseDragMode == MODE_UNDECIDED)
{
int tdx = Math.abs(where.x - pressXCoord);
int tdy = Math.abs(where.y - pressYCoord);
if(tdx/2 >= tdy+1) mouseDragMode = MODE_HORIZONTAL;
else if(tdy/2 >= tdx+1) mouseDragMode = MODE_VERTICAL;
}
boolean isShift, isCtrl, isShiftCtrl;
isShift = SwingUtilities.isRightMouseButton(ev) || ev.isShiftDown();
isCtrl = SwingUtilities.isMiddleMouseButton(ev) || ev.isControlDown();
isShiftCtrl = (isShift && isCtrl) || (SwingUtilities.isLeftMouseButton(ev) && SwingUtilities.isRightMouseButton(ev));
if(isShiftCtrl) sc_drag(dx, dy, ev);
else if(isCtrl) c_drag(dx, dy, ev);
else if(isShift) s_drag(dx, dy, ev);
else drag(dx, dy, ev);
lastXCoord = where.x;
lastYCoord = where.y;
}
public void mouseMoved(MouseEvent ev)
{}
//}}}
//{{{ Mouse click listners
//##################################################################################################
public void mouseClicked(MouseEvent ev)
{
// Handle picking, etc. here
int x = ev.getX(), y = ev.getY();
KPoint p = null;
if(kMain.getKinemage() != null)
p = kCanvas.getEngine().pickPoint(x, y, services.doSuperpick.isSelected());
// otherwise, we just create a nonsensical warning message about stereo picking
/* Mouse debugging * /
// Java: RMB == Meta, MMB == Alt
// Apple: RMB == Control (not in Java?) (2 btn but not 3 btn mouse?)
if(SwingUtilities.isLeftMouseButton(ev)) SoftLog.err.print("Left ");
if(SwingUtilities.isMiddleMouseButton(ev)) SoftLog.err.print("Middle ");
if(SwingUtilities.isRightMouseButton(ev)) SoftLog.err.print("Right ");
if(ev.isShiftDown()) SoftLog.err.print("Shift ");
if(ev.isControlDown()) SoftLog.err.print("Control ");
if(ev.isMetaDown()) SoftLog.err.print("Meta ");
if(ev.isAltDown()) SoftLog.err.print("Alt ");
SoftLog.err.println(Integer.toBinaryString(ev.getModifiers()));
/* Mouse debugging */
boolean isShift, isCtrl;
isShift = SwingUtilities.isRightMouseButton(ev) || ev.isShiftDown();
isCtrl = SwingUtilities.isMiddleMouseButton(ev) || ev.isControlDown();
/**
* This "if" statement is to correct for a Java 1.5 issue where
* pressing mouse and releasing counts as a click as well, so
* using the right mouse to zoom would also recenter if you released
* over a point. See java bug # 5039416.
**/
if (mouseDragMode.equals(MODE_UNDECIDED)) {
if(isShift && isCtrl) sc_click(x, y, p, ev);
else if(isCtrl) c_click(x, y, p, ev);
else if(isShift) s_click(x, y, p, ev);
else click(x, y, p, ev);
}
}
public void mouseEntered(MouseEvent ev)
{}
public void mouseExited(MouseEvent ev)
{}
public void mousePressed(MouseEvent ev)
{
Dimension dim = kCanvas.getCanvasSize();
isNearBottom = isNearTop = false;
if(ev.getY() < (dim.height / 6)) isNearTop = true;
else if(ev.getY() > ((dim.height * 5) / 6)) isNearBottom = true;
Point where = ev.getPoint();
pressXCoord = lastXCoord = where.x;
pressYCoord = lastYCoord = where.y;
mouseDragMode = MODE_UNDECIDED;
}
public void mouseReleased(MouseEvent ev)
{}
//}}}
//{{{ Window listeners
//##################################################################################################
public void windowActivated(WindowEvent ev) {}
public void windowClosed(WindowEvent ev) {}
public void windowClosing(WindowEvent ev) { parent.activateDefaultTool(); }
public void windowDeactivated(WindowEvent ev) {}
public void windowDeiconified(WindowEvent ev) {}
public void windowIconified(WindowEvent ev) {}
public void windowOpened(WindowEvent ev) {}
//}}}
//{{{ onArrowUp/Down/Right/Left
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowUp(ActionEvent ev)
{
// fake event, except for modifiers
MouseEvent mev = new MouseEvent(kCanvas, 0, 0, ev.getModifiers(), 0, 0, 0, false);
mouseWheelMoved(mev, -1);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowDown(ActionEvent ev)
{
// fake event, except for modifiers
MouseEvent mev = new MouseEvent(kCanvas, 0, 0, ev.getModifiers(), 0, 0, 0, false);
mouseWheelMoved(mev, 1);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowRight(ActionEvent ev)
{
KingView v = kMain.getView();
if(v == null) return;
v.rotateY((float)(Math.PI/180.0) * 2f);
kCanvas.repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowLeft(ActionEvent ev)
{
KingView v = kMain.getView();
if(v == null) return;
v.rotateY((float)(Math.PI/180.0) * -2f);
kCanvas.repaint();
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
}
//}}}
//{{{ overpaintCanvas
//##################################################################################################
/**
* Called by KinCanvas after all kinemage painting is complete,
* this gives the tools a chance to write additional info
* (e.g., point IDs) to the graphics area.
* @param painter the Painter that can paint on the current canvas
*/
public void overpaintCanvas(Painter painter)
{
}
//}}}
//{{{ getToolsMenuItem, onToolActivate, getToolPanel, getHelpAnchor, toString
//##################################################################################################
/**
* Creates a new JRadioButtonMenuItem to be displayed in the Tools menu,
* which will allow the user to access function(s) associated
* with this Tool.
*
* A tool that wants to return null here should probably be a Plugin instead.
* @return a JRadioButtonMenuItem (not just a regular JMenuItem)
*/
public JMenuItem getToolsMenuItem()
{
JRadioButtonMenuItem btn = new JRadioButtonMenuItem(
new ReflectiveAction(this.toString(), null, this, "onToolActivate"));
btn.setSelected(false);
return btn;
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onToolActivate(ActionEvent ev)
{
parent.toolActivated(this);
}
/** Returns a component with controls and options for this tool */
protected Container getToolPanel()
{ return null; }
/**
* Returns an anchor marking a place within king-manual.html
* that is the help for this tool. This is called by the default
* implementation of getHelpURL()
.
* If you override that function, you can safely ignore this one.
* @return for example, "#navigate-tool" (or null)
*/
public String getHelpAnchor()
{ return "#navigate-tool"; }
public String toString() { return "Navigate"; }
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/EDMapPlotter.java 0000644 0000000 0000000 00000013063 11531212674 020120 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.isosurface.*;
//}}}
/**
* EDMapPlotter
creates an isosurface
* by instantiating VectorPoints directly.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Tue Mar 4 14:35:25 EST 2003
*/
public class EDMapPlotter implements EdgePlotter
{
//{{{ Constants
DecimalFormat df2 = driftwood.util.Strings.usDecimalFormat("0.##");
//}}}
//{{{ Variable definitions
//##################################################################################################
KList list;
VectorPoint prevV;
TrianglePoint prevT;
String level;
Object mode;
boolean unpickable;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
* @param mode is one of the MarchingCubes.MODE_xxx constants.
*/
public EDMapPlotter(boolean pickable, Object mode)
{
list = null;
prevV = null;
prevT = null;
level = null;
unpickable = !pickable;
if(mode != MarchingCubes.MODE_MESH && mode != MarchingCubes.MODE_TRIANGLE)
throw new IllegalArgumentException("Illegal MarchingCubes MODE constant: "+mode);
this.mode = mode;
}
//}}}
//{{{ startIsosurface
//##################################################################################################
/**
* Called before the isosurface generator starts plotting anything.
* Gives this plotter a chance to initialize any needed data structures, streams, etc.
* @param lvl the level for which an isosurface will be generated
*/
public void startIsosurface(double lvl)
{
level = df2.format(lvl);
list = new KList();
list.setName("ED map @ "+level);
list.setType((mode == MarchingCubes.MODE_MESH ? KList.VECTOR : KList.TRIANGLE));
list.setWidth(1);
if(mode == MarchingCubes.MODE_TRIANGLE)
list.alpha = (int)(0.25 * 255);
}
//}}}
//{{{ startCell
//##################################################################################################
/**
* Called before the isosurface generator starts each cell.
* @param i the minimum x index of the current cell
* @param j the minimum y index of the current cell
* @param k the minimum z index of the current cell
*/
public void startCell(int i, int j, int k)
{
prevV = null;
prevT = null;
}
//}}}
//{{{ plotEdge
//##################################################################################################
/**
* Called for each edge in the isosurface mesh.
* @param x the x coordinate of the current point
* @param y the y coordinate of the current point
* @param z the z coordinate of the current point
* @param lineto if true, a line should be drawn from the last point to this one.
* if false, the pen should move to this point without drawing.
*/
public void plotEdge(double x, double y, double z, boolean lineto)
{
KPoint p;
if(mode == MarchingCubes.MODE_MESH)
{
if(lineto) p = new VectorPoint(list, level, prevV);
else p = new VectorPoint(list, level, null);
prevV = (VectorPoint)p;
}
else//mode == MarchingCubes.MODE_TRIANGLE
{
if(lineto) p = new TrianglePoint(list, level, prevT);
else p = new TrianglePoint(list, level, null);
prevT = (TrianglePoint)p;
}
p.setOrigX(x);
p.setOrigY(y);
p.setOrigZ(z);
p.setUnpickable(unpickable);
list.add(p);
}
//}}}
//{{{ endCell
//##################################################################################################
/**
* Called after the isosurface generator finishes each cell.
* @param i the minimum x index of the current cell
* @param j the minimum y index of the current cell
* @param k the minimum z index of the current cell
*/
public void endCell(int i, int j, int k)
{
}
//}}}
//{{{ endIsosurface
//##################################################################################################
/**
* Called after the isosurface generator finishes plotting everything.
* Gives this plotter a chance to release memory, close streams, etc.
* @param level the level for which an isosurface will be generated
*/
public void endIsosurface(double level)
{
}
//}}}
//{{{ getList, freeList
//##################################################################################################
/** Releases the last surface generated */
public void freeList()
{ list = null; }
/** Retrieves the last surface generated (could be null)*/
public KList getList()
{ return list; }
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/FileDropHandler.java 0000644 0000000 0000000 00000005314 11531212674 020622 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.util.*;
//}}}
/**
* FileDropHandler
allows Drag-n-Drop opening of kinemages
* on the KinCanvas -- but it requires Java 1.4.
* Thus, KiNG code should only reference this class via reflection,
* so as to preserve backwards compatibility with Java 1.3.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Thu Feb 26 15:31:04 EST 2004
*/
public class FileDropHandler extends TransferHandler
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
KingMain kMain;
//}}}
//{{{ Constructor(s)
//##############################################################################
public FileDropHandler(KingMain kMain, JComponent kCanvas)
{
super();
this.kMain = kMain;
kCanvas.setTransferHandler(this);
}
//}}}
//{{{ canImport
//##############################################################################
public boolean canImport(JComponent comp, DataFlavor[] transferFlavors)
{
// we can ignore comp because this handler isn't shared by multiple components
for(int i = 0; i < transferFlavors.length; i++)
{
if(DataFlavor.javaFileListFlavor.equals(transferFlavors[i]))
return true;
}
return false;
}
//}}}
//{{{ importData
//##############################################################################
public boolean importData(JComponent comp, Transferable t)
{
// we can ignore comp because this handler isn't shared by multiple components
if(canImport(comp, t.getTransferDataFlavors()))
{
try
{
KinfileIO io = kMain.getKinIO();
java.util.List filelist = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor);
for(Iterator iter = filelist.iterator(); iter.hasNext(); )
io.loadFile((File)iter.next(), null);
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
catch(UnsupportedFlavorException ex) { ex.printStackTrace(SoftLog.err); }
}
return false;
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/UIDisplayMenu.java 0000644 0000000 0000000 00000054440 11531212674 020314 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
//}}}
/**
* UIDisplayMenu
encapsulates all the functions
* listed in KiNG's "Display" menu.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Mon May 26 12:30:25 EDT 2003
*/
public class UIDisplayMenu //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ INNER CLASS: DispQualityList
//##################################################################################################
class DispQualityList extends MenuList
{
Map map;
public DispQualityList(Map stringToIntegerMap, Collection strings, String defaultItem)
{
super(strings, defaultItem);
map = stringToIntegerMap;
}
protected void itemSelected(Object item)
{
if(item == null) return;
KinCanvas canvas = kMain.getCanvas();
canvas.setQuality( ((Integer)map.get(item)).intValue() );
canvas.repaint();
}
}
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
JMenu menu = null;
JMenu aspectMenu = null;
JCheckBoxMenuItem cbPersp = null, cbBigMarkers = null, cbBigLabels = null, cbThickness = null,
cbThin = null, cbIntensity = null, cbBackground = null, cbMonochrome = null, cbColorByList = null,
cbStereo = null, cbCrosseye = null;
JCheckBoxMenuItem autoRockMenuItem = null;
// Timers, etc for auto-xxx functions
javax.swing.Timer autoRockTimer = null;
float rockStepSize = 0;
int rockStepCount = 0;
int rockMaxSteps = 0;
boolean rockRight = true;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public UIDisplayMenu(KingMain kmain)
{
kMain = kmain;
int steptime = kMain.prefs.getInt("autoRockCycleTime") / kMain.prefs.getInt("autoRockCycleSteps");
autoRockTimer = new javax.swing.Timer(steptime, new ReflectiveAction(null, null, this, "onDispAutoRockStep"));
autoRockTimer.setRepeats(true);
autoRockTimer.setCoalesce(false);
rockMaxSteps = kMain.prefs.getInt("autoRockCycleSteps") / 2;
rockStepCount = rockMaxSteps / 2;
rockStepSize = (float)Math.toRadians(2.0 * kMain.prefs.getDouble("autoRockDegrees") / (double)rockMaxSteps);
}
//}}}
//{{{ getMenu
//##################################################################################################
public JMenu getMenu()
{
if(menu != null) return menu;
menu = new JMenu("Display");
menu.setMnemonic(KeyEvent.VK_D);
aspectMenu = new JMenu("Aspects");
aspectMenu.setMnemonic(KeyEvent.VK_A);
menu.add(aspectMenu);
rebuildAspectsMenu();
menu.addSeparator();
cbPersp = new JCheckBoxMenuItem(new ReflectiveAction("Use perspective", null, this, "onDispPersp"));
cbPersp.setMnemonic(KeyEvent.VK_U);
cbPersp.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)); // 0 => no modifiers
menu.add(cbPersp);
cbStereo = new JCheckBoxMenuItem(new ReflectiveAction("Use stereo", null, this, "onDispStereo"));
cbStereo.setMnemonic(KeyEvent.VK_S);
cbStereo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0)); // 0 => no modifiers
menu.add(cbStereo);
cbCrosseye = new JCheckBoxMenuItem(new ReflectiveAction("Crosseye stereo", null, this, "onDispCrosseye"));
cbCrosseye.setMnemonic(KeyEvent.VK_C);
cbCrosseye.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0)); // 0 => no modifiers
menu.add(cbCrosseye);
menu.addSeparator();
cbBigMarkers = new JCheckBoxMenuItem(new ReflectiveAction("Big markers", null, this, "onDispBigMarkers"));
cbBigMarkers.setMnemonic(KeyEvent.VK_B);
cbBigMarkers.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0));
menu.add(cbBigMarkers);
cbBigLabels = new JCheckBoxMenuItem(new ReflectiveAction("Big labels", null, this, "onDispBigLabels"));
cbBigLabels.setMnemonic(KeyEvent.VK_G);
cbBigLabels.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0));
menu.add(cbBigLabels);
cbThickness = new JCheckBoxMenuItem(new ReflectiveAction("Cue by thickness", null, this, "onDispThickness"));
cbThickness.setMnemonic(KeyEvent.VK_T);
cbThickness.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.SHIFT_MASK));
menu.add(cbThickness);
cbThin = new JCheckBoxMenuItem(new ReflectiveAction("Thin lines", null, this, "onDispThin"));
cbThin.setMnemonic(KeyEvent.VK_N);
cbThin.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0)); // 0 => no modifiers
menu.add(cbThin);
Map map = new HashMap();
map.put("Standard", new Integer(KinCanvas.QUALITY_GOOD));
map.put("Better", new Integer(KinCanvas.QUALITY_BETTER));
map.put("Best", new Integer(KinCanvas.QUALITY_BEST));
map.put("OpenGL", new Integer(KinCanvas.QUALITY_JOGL));
Collection list = Arrays.asList(new String[] {"Standard", "Better", "Best", "OpenGL"});
String defQual = "Standard";
if(kMain.getCanvas().renderQuality == KinCanvas.QUALITY_BETTER)
defQual = "Better"; // for OS X
else if(kMain.getCanvas().renderQuality == KinCanvas.QUALITY_JOGL)
defQual = "OpenGL"; // for king_prefs:joglByDefault = true
JMenuItem submenu = new DispQualityList(map, list, defQual).getMenu();
submenu.setText("Rendering quality");
menu.add(submenu);
menu.addSeparator();
JMenuItem item = new JMenuItem(new ReflectiveAction("Set contrast...", null, this, "onDispContrast"));
item.setMnemonic(KeyEvent.VK_O);
//item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, 0)); // 0 => no modifiers
menu.add(item);
cbIntensity = new JCheckBoxMenuItem(new ReflectiveAction("Cue by intensity", null, this, "onDispIntensity"));
cbIntensity.setMnemonic(KeyEvent.VK_I);
cbIntensity.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, 0)); // 0 => no modifiers
menu.add(cbIntensity);
cbBackground = new JCheckBoxMenuItem(new ReflectiveAction("White background", null, this, "onDispBackground"));
cbBackground.setMnemonic(KeyEvent.VK_W);
cbBackground.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, 0)); // 0 => no modifiers
menu.add(cbBackground);
cbMonochrome = new JCheckBoxMenuItem(new ReflectiveAction("Monochrome", null, this, "onDispMonochrome"));
cbMonochrome.setMnemonic(KeyEvent.VK_M);
menu.add(cbMonochrome);
cbColorByList = new JCheckBoxMenuItem(new ReflectiveAction("Color by list", null, this, "onDispColorByList"));
cbColorByList.setMnemonic(KeyEvent.VK_L);
cbColorByList.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0)); // 0 => no modifiers
menu.add(cbColorByList);
menu.addSeparator();
autoRockMenuItem = new JCheckBoxMenuItem(new ReflectiveAction("Auto-rock", null, this, "onDispAutoRockStartStop"));
autoRockMenuItem.setMnemonic(KeyEvent.VK_R);
autoRockMenuItem.setSelected(autoRockTimer.isRunning());
autoRockMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0)); // 0 => no modifiers
menu.add(autoRockMenuItem);
syncCheckboxes();
return menu;
}
//}}}
//{{{ syncCheckboxes
//##################################################################################################
/**
* Adjusts the selection state of checkboxes in the Display menu to match parameters in the engine
*/
void syncCheckboxes()
{
if(menu == null) return;
KinCanvas kCanvas = kMain.getCanvas();
Engine engine = kCanvas.getEngine();
cbPersp.setSelected(engine.usePerspective);
cbStereo.setSelected(engine.useStereo);
cbCrosseye.setSelected(engine.stereoRotation < 0);
cbBigMarkers.setSelected(engine.bigMarkers);
cbBigLabels.setSelected(engine.bigLabels);
cbThickness.setSelected(engine.cueThickness);
cbThin.setSelected(engine.thinLines);
cbIntensity.setSelected(engine.cueIntensity);
cbBackground.setSelected(engine.whiteBackground);
cbMonochrome.setSelected(engine.monochrome);
cbColorByList.setSelected(engine.colorByList);
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
cbPersp.setSelected(kin.atPerspective);
cbThickness.setSelected(!kin.atOnewidth);
cbThin.setSelected(kin.atThinline);
cbBackground.setSelected(kin.atWhitebackground);
cbColorByList.setSelected(kin.atListcolordominant);
}
//}}}
//{{{ rebuildAspectsMenu
//##################################################################################################
/**
* Refills the Display | Aspects menu from the
* specified iterator of Aspect objects
*/
public void rebuildAspectsMenu()
{
if(aspectMenu == null) return;
aspectMenu.removeAll();
JMenuItem item;
JRadioButtonMenuItem ritem;
ButtonGroup rgroup = new ButtonGroup();
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
ritem = new JRadioButtonMenuItem(new ReflectiveAction("Aspects off", null, this, "onDisplayAspectsOff"));
ritem.setMnemonic(KeyEvent.VK_O);
ritem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SLASH, 0)); // 0 => no modifiers
rgroup.add(ritem);
aspectMenu.add(ritem);
aspectMenu.addSeparator();
int i = 1;
for(Iterator iter = kin.getAspectIterator(); iter.hasNext(); i++)
{
Aspect aspect = (Aspect)iter.next();
ritem = new JRadioButtonMenuItem(new ReflectiveAction((i+" "+aspect.getName()), null, aspect, "selectedFromMenu"));
rgroup.add(ritem);
aspectMenu.add(ritem);
}
/* Next / Previous */
if(i > 1) aspectMenu.addSeparator();
item = new JMenuItem(new ReflectiveAction("Next aspect", null, this, "onDisplayAspectsNext"));
item.setMnemonic(KeyEvent.VK_N);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET, 0)); // 0 => no modifiers
aspectMenu.add(item);
item = new JMenuItem(new ReflectiveAction("Previous aspect", null, this, "onDisplayAspectsPrevious"));
item.setMnemonic(KeyEvent.VK_P);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, 0));
aspectMenu.add(item);
/* Next / Previous */
}
else
{
item = new JMenuItem("No aspects available");
item.setEnabled(false);
aspectMenu.add(item);
}
// This step is ESSENTIAL for the menu to appear & keep working!
//menubar.revalidate();
}
//}}}
//{{{ onDisplayAspects{Off, Next, Previous}
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDisplayAspectsOff(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.currAspect = null;
kMain.notifyChange(KingMain.EM_DISPLAY);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDisplayAspectsNext(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
Aspect currAspect = kin.getCurrentAspect();
if(currAspect == null) // if nothing's selected yet
{
Iterator iter = kin.getAspectIterator();
if(iter.hasNext())
{
currAspect = (Aspect)iter.next();
if(currAspect != null) currAspect.selectedFromMenu(null);
}
}
else // if something's already selected
{
for(Iterator iter = kin.getAspectIterator(); iter.hasNext(); )
{
if(iter.next() == currAspect)
{
// If current was last, choose first
if(!iter.hasNext()) iter = kin.getAspectIterator();
// If there's a next one, choose it
if(iter.hasNext())
{
currAspect = (Aspect)iter.next();
if(currAspect != null) currAspect.selectedFromMenu(null);
break;
}
}
}
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDisplayAspectsPrevious(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
Aspect currAspect = kin.getCurrentAspect();
if(currAspect == null) // if nothing's selected yet
{
Iterator iter = kin.getAspectIterator();
while(iter.hasNext())
currAspect = (Aspect)iter.next();
if(currAspect != null) currAspect.selectedFromMenu(null);
}
else // if something's already selected
{
Aspect curr, prev = null;
for(Iterator iter = kin.getAspectIterator(); iter.hasNext(); )
{
curr = (Aspect)iter.next();
if(curr == currAspect)
{
// If current was first, choose last
if(prev == null)
{
while(iter.hasNext())
currAspect = (Aspect)iter.next();
if(currAspect != null)
{
currAspect.selectedFromMenu(null);
break;
}
}
// If there's a previous one, choose it
else
{
prev.selectedFromMenu(null);
break;
}
}
prev = curr;
}
}
}
//}}}
//{{{ onDisp{Persp, Stereo, Crosseye}
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispPersp(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
kin.atPerspective = cbPersp.isSelected();
// Deliberately don't mark kin as modified
kMain.notifyChange(KingMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispStereo(ActionEvent ev)
{
if(kMain.getCanvas() != null)
{
Engine engine = kMain.getCanvas().getEngine();
if(engine != null) engine.useStereo = cbStereo.isSelected();
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispCrosseye(ActionEvent ev)
{
if(kMain.getCanvas() != null)
{
Engine engine = kMain.getCanvas().getEngine();
if(engine != null)
{
engine.stereoRotation
= (cbCrosseye.isSelected() ^ engine.stereoRotation < 0) ? -engine.stereoRotation : engine.stereoRotation;
}
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
//}}}
//{{{ onDisp{BigMarkers, BigLabels, Thickness, Thin}
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispBigMarkers(ActionEvent ev)
{
if(kMain.getCanvas() != null)
{
Engine engine = kMain.getCanvas().getEngine();
if(engine != null) engine.bigMarkers = cbBigMarkers.isSelected();
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispBigLabels(ActionEvent ev)
{
if(kMain.getCanvas() != null)
{
Engine engine = kMain.getCanvas().getEngine();
if(engine != null) engine.bigLabels = cbBigLabels.isSelected();
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispThickness(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
kin.atOnewidth = ! cbThickness.isSelected();
// Deliberately don't mark kin as modified
kMain.notifyChange(KingMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispThin(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
kin.atThinline = cbThin.isSelected();
// Deliberately don't mark kin as modified
// Assume we don't want width depth cues with thinline
if(cbThin.isSelected())
{
kin.atOnewidth = true;
cbThickness.setSelected(false);
}
kMain.notifyChange(KingMain.EM_DISPLAY);
}
}
//}}}
//{{{ onDisp{Intensity, Background, Monochrome, ColorByList}
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispIntensity(ActionEvent ev)
{
if(kMain.getCanvas() != null)
{
Engine engine = kMain.getCanvas().getEngine();
if(engine != null) engine.cueIntensity = cbIntensity.isSelected();
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispBackground(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
kin.atWhitebackground = cbBackground.isSelected();
// Deliberately don't mark kin as modified
kMain.notifyChange(KingMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispMonochrome(ActionEvent ev)
{
if(kMain.getCanvas() != null)
{
Engine engine = kMain.getCanvas().getEngine();
if(engine != null)
{
boolean sel = cbMonochrome.isSelected();
engine.monochrome = sel;
// assume we want white background with monochrome
if(sel == true)
{
engine.whiteBackground = true;
cbBackground.setSelected(true);
}
}
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispColorByList(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
kin.atListcolordominant = cbColorByList.isSelected();
// Deliberately don't mark kin as modified
kMain.notifyChange(KingMain.EM_DISPLAY);
}
}
//}}}
//{{{ onDisplayAutoRock{StartStop, Step}
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispAutoRockStartStop(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k == null) return;
if(autoRockMenuItem.isSelected())
{
rockStepCount = rockMaxSteps / 2;
rockRight = true;
autoRockTimer.start();
}
else
{
autoRockTimer.stop();
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispAutoRockStep(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k == null) return;
KingView v = k.getCurrentView();
if(rockStepCount >= rockMaxSteps)
{
rockStepCount = 0;
rockRight = !rockRight;
}
// Stiff bouncing:
//if(rockRight) v.rotateY( rockStepSize);
//else v.rotateY(-rockStepSize);
// Slows and pauses at either end:
if(rockRight) v.rotateY((float)(2 * rockStepSize * Math.sin((Math.PI*rockStepCount)/rockMaxSteps)));
else v.rotateY((float)(2 * -rockStepSize * Math.sin((Math.PI*rockStepCount)/rockMaxSteps)));
rockStepCount++;
kMain.notifyChange(kMain.EM_DISPLAY);
}
//}}}
//{{{ onDispContrast
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDispContrast(ActionEvent ev)
{
JSlider slider = new JSlider(0, 100, 50);
int response = JOptionPane.showConfirmDialog(kMain.getTopWindow(),
slider, "Set display contrast",
JOptionPane.OK_CANCEL_OPTION , JOptionPane.PLAIN_MESSAGE);
if(response == JOptionPane.OK_OPTION)
{
int contrast = slider.getValue() - 50;
KPalette.setContrast(1.0 + contrast/50.0);
kMain.notifyChange(kMain.EM_DISPLAY);
}
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/KingMain.java 0000644 0000000 0000000 00000046723 11531212674 017326 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
//import java.awt.geom.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.plaf.metal.MetalLookAndFeel;
import driftwood.util.*;
import driftwood.isosurface.*;
import driftwood.gui.*;
//}}}
/**
* KingMain
is the control center of the King program.
*
*
Begun on Mon Apr 22 17:18:36 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis
*/
public class KingMain implements WindowListener, KinemageSignalSubscriber
{
static
{
// This allows JMenus to overlap the JOGL canvas, which stopped
// happening automatically with the release of Java 1.5.
// This should happen once, before any KingMains are created.
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
}
public static void main(String[] args) { new KingMain(args).Main(); }
//{{{ Event masks
/** Event mask: current kinemage has been switched */
public static final int EM_SWITCH = 0x00000001;
/** Event mask: all kinemages have been closed */
public static final int EM_CLOSEALL = 0x00000002;
/** Event mask: new view was chosen from the Views menu */
public static final int EM_NEWVIEW = 0x00000004;
/** Event mask: large-scale editing was performed (group/list level) */
public static final int EM_EDIT_GROSS = 0x00000008;
/** Event mask: small-scale editing was performed (point level) */
public static final int EM_EDIT_FINE = 0x00000010;
/** Event mask: buttons were turned on/off, or points became (in)visible for some other reason (master, animate) */
public static final int EM_ON_OFF = 0x00000020;
/** Event mask: display mode changed */
public static final int EM_DISPLAY = 0x00000040;
/** Event mask: current kinemage has been closed */
public static final int EM_CLOSE = 0x00000080;
/** Event mask: preferences were updated */
public static final int EM_PREFS = 0x00000100;
//}}}
//{{{ Variables
//##################################################################################################
// Used for counting # of clones still alive, so we don't
// call System.exit() prematurely!
static int instanceCount = 0;
KingPrefs prefs = null;
KinStable kinStable = null;
KinfileIO kinIO = null;
KinCanvas kinCanvas = null;
UIMenus uiMenus = null;
UIText uiText = null;
KinTree kinTree = null;
MainWindow mainWin = null;
ContentPane contentPane = null;
JApplet theApplet = null;
boolean isAppletFlat = true;
ArrayList filesToOpen = null;
boolean doMerge = true;
//}}}
//{{{ Constructors
//##################################################################################################
/** Simple constructor for embedded apps */
public KingMain() { this(new String[] {}); }
/**
* Constructor for application
*/
public KingMain(String[] args)
{
// This prevents number formatting problems when writing kins in
// e.g. Germany. Kludgy, but KiNG isn't internationalized anyway.
// Ideally, this will go away one day.
try { Locale.setDefault(Locale.US); }
catch(SecurityException ex) { SoftLog.err.println("Can't change to US locale; numbers may be garbled on kinemage write."); }
prefs = new KingPrefs();
if(prefs.getBoolean("checkNewVersion"))
{
// "Timeout" after 2.000 seconds
try { prefs.checkVersion(new URL("http://kinemage.biochem.duke.edu/downloads/software/king/king.version.props"), 2000); }
catch(MalformedURLException ex) { ex.printStackTrace(SoftLog.err); }
}
parseArguments(args);
instanceCount++;
}
/**
* Constructor for applet
*/
public KingMain(JApplet plet, boolean isFlat)
{
prefs = new KingPrefs();
theApplet = plet;
isAppletFlat = isFlat;
// Load custom config from URL
String king_prefs = theApplet.getParameter("king_prefs");
if(king_prefs != null) try
{
URL prefsURL = new URL(theApplet.getDocumentBase(), king_prefs);
prefs.loadFromURL(prefsURL);
}
catch(MalformedURLException ex)
{ SoftLog.err.println(" king_prefs specified an unresolvable URL."); }
instanceCount++;
}
//}}}
//{{{ createComponents
//##################################################################################################
public void createComponents() { createComponents(true, true); }
/**
* Creates all the major components of a running KiNG instance:
* KinStable, ContentPane, KinfileIO, KinCanvas, UIMenus, UIText, KinTree.
* Call this after the constructor but before trying to assemble the overall GUI.
*/
public void createComponents(boolean useButtons, boolean useSliders)
{
kinStable = new KinStable(this);
contentPane = new ContentPane(this); // doesn't create GUI yet
kinIO = new KinfileIO(this); // progress dlg. references main window
kinCanvas = new KinCanvas(this);
uiMenus = new UIMenus(this);
uiText = new UIText(this);
kinTree = new KinTree(this);
contentPane.buildGUI(useButtons, useSliders);
}
//}}}
//{{{ shutdown
//##################################################################################################
/**
* Initiates shutdown, albeit in a crude way. Called by Kinglet.stop() and the window close listeners.
*/
public void shutdown()
{
if(uiText != null) uiText.shutdown();
if(mainWin != null) mainWin.shutdown();
if(kinCanvas != null) kinCanvas.shutdown();
instanceCount--;
if(instanceCount <= 0 && theApplet == null)
{
try { System.exit(0); } catch(Throwable t) {} //catch(SecurityException ex) {}
}
}
//}}}
//{{{ Main
//##################################################################################################
/**
* Main() function for running as an application
*/
public void Main()
{
// This compensates for incorrect drawing primitives on Mac OS X
//try { System.setProperty("apple.awt.antialiasing", "on"); }
//catch(SecurityException ex) { SoftLog.err.println("Not allowed to activate antialiasing."); }
// No effect -- must be done using -D from Java cmd line
// Start in a reasonable directory if launched by double-click / drag-n-drop
try {
if(System.getProperty("user.dir").equals("/Applications"))
System.setProperty("user.dir", System.getProperty("user.home"));
//System.err.println("Current dir: "+System.getProperty("user.dir"));
} catch(Exception ex) {}//{ ex.printStackTrace(); }
// It's just too hard to change this after we've already started up!
float magnification = prefs.getFloat("fontMagnification");
if(magnification != 1)
{
MetalLookAndFeel.setCurrentTheme(new MagnifiedTheme(magnification));
// This forces initialization of the LAF, which keeps Java 1.5
// from replacing our theme with their "Ocean" theme.
try { UIManager.setLookAndFeel( UIManager.getLookAndFeel() ); }
catch(Exception ex) { ex.printStackTrace(); }
}
if(!SoftLog.replaceSystemStreams())
SoftLog.err.println("Unable to subvert System.err; some exception traces may be lost.");
if(theApplet == null || !isAppletFlat)
mainWin = new MainWindow(this); // doesn't create GUI yet, but other dlgs may depend on this one (?)
createComponents(); // actually creates most of the stuff KiNG uses
if(theApplet == null || !isAppletFlat)
{
mainWin.setContentPane(contentPane);
mainWin.setJMenuBar(uiMenus.getMenuBar());
mainWin.addWindowListener(this);
mainWin.pack();
mainWin.setVisible(true);
if(prefs.getBoolean("textOpenOnStart"))
uiText.cascadeBehind(mainWin);
}
else
{
kinCanvas.setPreferredSize(null); // so we don't crowd off other components
kinCanvas.setMinimumSize(null);
theApplet.setContentPane(contentPane);
theApplet.setJMenuBar(uiMenus.getMenuBar());
theApplet.validate();
// make sure text window gets opened as needed
}
// Drag & Drop support for opening kinemages
if(theApplet == null)
{
// Mac OS X only! - adds support for Drag & Drop to Dock icon and for program launch
try {
//MacDropTarget.bindTo(this);
Class macDropClass = Class.forName("king.MacDropTarget");
Method bindTo = macDropClass.getMethod("bindTo", new Class[] {KingMain.class});
bindTo.invoke(null, new Object[] {this});
} catch(Throwable t) {}
// Java 1.4+ only! - adds support for Drag & Drop to KinCanvas
try {
//new FileDropHandler(this, kinCanvas);
Class dropClass = Class.forName("king.FileDropHandler");
Constructor dropConstr = dropClass.getConstructor(new Class[] { KingMain.class, KinCanvas.class });
dropConstr.newInstance(new Object[] { this, kinCanvas });
} catch(Throwable t) {}
}
if(theApplet == null)
SwingUtilities.invokeLater(new ReflectiveRunnable(this, "loadFiles"));
else
SwingUtilities.invokeLater(new ReflectiveRunnable(this, "appletLoadFiles"));
}
//}}}
//{{{ loadFiles
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void loadFiles()
{
if(filesToOpen == null || filesToOpen.size() <= 0) return;
Kinemage kin = null;
if(doMerge && filesToOpen.size() > 1) kin = new Kinemage(KinfileParser.DEFAULT_KINEMAGE_NAME+"1");
KinfileIO io = this.getKinIO();
for(Iterator iter = filesToOpen.iterator(); iter.hasNext(); )
{ io.loadFile((File)iter.next(), kin); }
if(kin != null) this.getStable().append(Arrays.asList(new Kinemage[] {kin}));
}
//}}}
//{{{ appletLoadFiles, getAppletKinURL
//##################################################################################################
/**
* File loading in event dispatch thread
*/
public void appletLoadFiles()
{
KinCanvas kCanvas = this.getCanvas();
ToolBox toolbox;
if(kCanvas == null) toolbox = null;
else toolbox = kCanvas.getToolBox();
try
{
URL kinURL = getAppletKinURL();
if(kinURL != null) this.getKinIO().loadURL(kinURL, null);
}
catch(MalformedURLException ex)
{ SoftLog.err.println(" kinSource specified an unresolvable URL."); }
// Try multiple names for this parameter
boolean isOmap = false;
String mapsrc = theApplet.getParameter("xmap");
if(mapsrc == null) { mapsrc = theApplet.getParameter("omap"); isOmap = true; }
if(mapsrc != null && toolbox != null)
{
try
{
URL mapURL = new URL(theApplet.getDocumentBase(), mapsrc);
CrystalVertexSource map;
if(isOmap)
{ map = new OMapVertexSource(mapURL.openStream()); }
else
{ map = new XplorVertexSource(mapURL.openStream()); }
new EDMapWindow(toolbox, map, mapURL.getFile());
}
catch(MalformedURLException ex)
{ SoftLog.err.println(" xmap/omap specified an unresolvable URL."); }
catch(IOException ex)
{
JOptionPane.showMessageDialog(this.getTopWindow(),
"An I/O error occurred while loading the file:\n"+ex.getMessage(),
"Sorry!", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace(SoftLog.err);
}
catch(IllegalArgumentException ex)
{
JOptionPane.showMessageDialog(this.getTopWindow(),
"Wrong map format was chosen, or map is corrupt:\n"+ex.getMessage(),
"Sorry!", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace(SoftLog.err);
}
}
}
/** Returns the URL of the primary kinemage this applet was invoked to show, or null for none. */
public URL getAppletKinURL() throws MalformedURLException
{
// Try multiple names for this parameter
String kinsrc = theApplet.getParameter("kinSource");
if(kinsrc == null) kinsrc = theApplet.getParameter("kinFile");
if(kinsrc == null) kinsrc = theApplet.getParameter("kinURL");
if(kinsrc == null) kinsrc = theApplet.getParameter("kinemage");
if(kinsrc == null) kinsrc = theApplet.getParameter("kin");
if(kinsrc != null) return new URL(theApplet.getDocumentBase(), kinsrc);
else return null;
}
//}}}
//{{{ signalKinemage, notifyChange
//##################################################################################################
/**
* A call to this method indicates that the specified
* kinemage has changed somehow.
*
*
This method will be called in response to KinemageSignal.signalKinemage().
*
* @param kinemage the Kinemage object that has changed
* @param bitmask a set of flags describing which properties have changed.
*/
public void signalKinemage(Kinemage kinemage, int bitmask)
{
int evmask = 0;
if((bitmask & APPEARANCE) != 0)
evmask |= EM_ON_OFF | EM_DISPLAY | EM_NEWVIEW | EM_EDIT_FINE;
//evmask |= EM_ON_OFF | EM_DISPLAY | EM_EDIT_FINE;
if((bitmask & STRUCTURE) != 0)
evmask |= EM_SWITCH | EM_EDIT_GROSS; // force menus to be remade
if(evmask != 0) this.notifyChange(evmask);
}
/**
* Notifies all existing sub-components of a change to the state of the program.
* Only notifies components directly owned by KingMain;
* for instance KinCanvas is reponsible for propagating this to Engine.
* @param event_mask the bitwise OR of the flag(s) representing the change
*/
public void notifyChange(int event_mask)
{
if(kinStable != null) kinStable.notifyChange(event_mask);
if(contentPane != null) contentPane.notifyChange(event_mask);
if(kinIO != null) kinIO.notifyChange(event_mask);
if(kinCanvas != null) kinCanvas.notifyChange(event_mask);
if(uiMenus != null) uiMenus.notifyChange(event_mask);
if(kinTree != null) kinTree.notifyChange(event_mask);
}
//}}}
//{{{ getXXX functions
//##################################################################################################
/** Returns the object holding our content: either a JFrame or a JApplet. Never null. */
public Container getContentContainer() { return (mainWin == null ? (Container)theApplet : (Container)mainWin); }
/** Returns the ContentPane object that holds all the GUI elements. Never null. */
public ContentPane getContentPane() { return contentPane; }
/** Returns the top-level window, if there is one; null otherwise. */
public Frame getTopWindow() { return mainWin; }
/** Returns the data model that holds all data for this session (never null) */
public KinStable getStable() { return kinStable; }
/** Returns the kinemage reader/writer (never null) */
public KinfileIO getKinIO() { return kinIO; }
/** Returns the active drawing canvas (never null) */
public KinCanvas getCanvas() { return kinCanvas; }
/** Returns the applet this was spawned from (may be null) */
public JApplet getApplet() { return theApplet; }
/** Returns the collection of UI actions and menus that manage user input (may be null) */
public UIMenus getMenus() { return uiMenus; }
/** Returns the text storage/edit/display system (never null) */
public UIText getTextWindow() { return uiText; }
/** Returns the tree controller (may be null) */
public KinTree getKinTree() { return kinTree; }
/** Returns the preferences storage object */
public KingPrefs getPrefs() { return prefs; }
/** Convenience function for getStable().getKinemage().getTreeModel() (may be null) */
public DefaultTreeModel getTreeModel()
{
Kinemage kin = kinStable.getKinemage();
if(kin == null) return null;
return kin.getTreeModel();
}
/** Convenience function for getStable().getKinemage() (may be null) */
public Kinemage getKinemage()
{
return kinStable.getKinemage();
}
/** Convenience function for getStable().getKinemage().getCurrentView() (may be null) */
public KingView getView()
{
Kinemage kin = kinStable.getKinemage();
if(kin == null) return null;
return kin.getCurrentView();
}
//}}}
//{{{ parseArguments
//##################################################################################################
// Interpret command-line arguments
void parseArguments(String[] args)
{
filesToOpen = new ArrayList();
String arg;
for(int i = 0; i < args.length; i++)
{
arg = args[i];
// this is an option
if(arg.startsWith("-"))
{
if(arg.equals("-h") || arg.equals("-help")) {
SoftLog.err.println("Help not available. Sorry!");
System.exit(0);
} else if(arg.equals("-version")) {
SoftLog.err.println("KingMain, version "+getPrefs().getString("version")+"\nCopyright (C) 2002-2003 by Ian W. Davis");
System.exit(0);
} else if(arg.equals("-m") || arg.equals("-merge")) {
doMerge = true;
} else if(arg.equals("-s") || arg.equals("-single")) {
doMerge = false;
} else {
SoftLog.err.println("*** Unrecognized option: "+arg);
}
}
// this is a file, etc.
else
{
filesToOpen.add(new File(arg));
}
}
}
//}}}
//{{{ Window events
//##################################################################################################
public void windowActivated(WindowEvent ev) {}
public void windowClosed(WindowEvent ev) {}
public void windowClosing(WindowEvent ev)
{
if(uiMenus != null) uiMenus.onFileExit(null);
else shutdown();
}
public void windowDeactivated(WindowEvent ev) {}
public void windowDeiconified(WindowEvent ev) {}
public void windowIconified(WindowEvent ev) {}
public void windowOpened(WindowEvent ev) {}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/ViewEditor.java 0000644 0000000 0000000 00000021130 11531212674 017673 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.gui.*;
//}}}
/**
* ViewEditor
has not yet been documented.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Thu Dec 5 09:46:29 EST 2002
*/
public class ViewEditor //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
JDialog dialog;
JList list;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public ViewEditor(KingMain kmain)
{
kMain = kmain;
dialog = new JDialog(kMain.getTopWindow(), "Edit views", true);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
list = new FatJList(0, 20);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setVisibleRowCount(12);
list.setBorder( BorderFactory.createEtchedBorder() );
JScrollPane listScroll = new JScrollPane(list);
JButton close = new JButton(new ReflectiveAction("Close", null, this, "onClose"));
JButton up = new JButton(new ReflectiveAction("Move up", kMain.prefs.moveUpIcon, this, "onMoveUp"));
JButton down = new JButton(new ReflectiveAction("Move down", kMain.prefs.moveDownIcon, this, "onMoveDown"));
JButton go = new JButton(new ReflectiveAction("Go to", null, this, "onGoTo"));
JButton gonext = new JButton(new ReflectiveAction("Go Next", kMain.prefs.stepForwardIcon, this, "onGoNext"));
JButton goprev = new JButton(new ReflectiveAction("Go Prev", kMain.prefs.stepBackIcon, this, "onGoPrev"));
JButton rename = new JButton(new ReflectiveAction("Rename", null, this, "onRename"));
JButton delete = new JButton(new ReflectiveAction("Delete", kMain.prefs.deleteIcon, this, "onDelete"));
up.setMnemonic(KeyEvent.VK_U);
down.setMnemonic(KeyEvent.VK_D);
rename.setMnemonic(KeyEvent.VK_R);
go.setMnemonic(KeyEvent.VK_G);
close.setMnemonic(KeyEvent.VK_C);
TablePane cp = new TablePane();
cp.insets(2).hfill(true).weights(0,0);
cp.save().weights(1,1).vfill(true).hfill(true).addCell(listScroll, 1, 9).restore();
cp.addCell(go).newRow();
cp.addCell(gonext).newRow();
cp.addCell(goprev).newRow();
cp.save().weights(0,1).insets(0).addCell(Box.createVerticalStrut(10)).restore().newRow();
cp.addCell(rename).newRow();
cp.addCell(delete).newRow();
cp.save().weights(0,1).insets(0).addCell(Box.createVerticalStrut(10)).restore().newRow();
cp.addCell(up).newRow();
cp.addCell(down).newRow();
cp.center().hfill(false).addCell(close, 2, 1);
dialog.setContentPane(cp);
dialog.getRootPane().setDefaultButton(close);
}
//}}}
//{{{ onClose, onMoveUp, onMoveDown
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onClose(ActionEvent ev)
{
dialog.dispose();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onMoveUp(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
KingView view = (KingView)list.getSelectedValue();
if(view == null) return;
java.util.List viewList = kin.getViewList();
ListIterator iter = viewList.listIterator();
Object swap = null, next = null;
do
{
swap = next;
next = iter.next();
} while(!view.equals(next));
if(swap != null)
{
iter.set(swap);
iter.previous(); //back to next...
iter.previous(); //back to swap...
iter.set(view);
}
kin.setModified(true);
// Re-fill the list so names are updated
list.setListData( viewList.toArray() );
list.setSelectedValue(view, true);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onMoveDown(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
KingView view = (KingView)list.getSelectedValue();
if(view == null) return;
java.util.List viewList = kin.getViewList();
ListIterator iter = viewList.listIterator();
while(!view.equals(iter.next())) {}
if(iter.hasNext())
{
Object swap = iter.next();
iter.set(view);
iter.previous(); //back to swap...
iter.previous(); //back to view...
iter.set(swap);
}
kin.setModified(true);
// Re-fill the list so names are updated
list.setListData( viewList.toArray() );
list.setSelectedValue(view, true);
}
//}}}
//{{{ onGoTo, onRename, onDelete
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onGoTo(ActionEvent ev)
{
KingView view = (KingView)list.getSelectedValue();
if(view == null) return;
view.selectedFromMenu(null);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onRename(ActionEvent ev)
{
KingView view = (KingView)list.getSelectedValue();
if(view == null) return;
String viewname = (String)JOptionPane.showInputDialog(kMain.getTopWindow(),
"Name for this view:",
"Rename view",
JOptionPane.PLAIN_MESSAGE,
null,//icon
null,//selections
view.getName());
if(viewname == null) return;
view.setName(viewname);
// Re-fill the list so names are updated
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.setModified(true);
list.setListData( kin.getViewList().toArray() );
list.setSelectedValue(view, true);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDelete(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
KingView view = (KingView)list.getSelectedValue();
if(view == null) return;
java.util.List viewList = kin.getViewList();
viewList.remove(view);
kin.setModified(true);
// Re-fill the list so names are updated
list.setListData( viewList.toArray() );
}
//}}}
//{{{ onGoNext, onGoPrev
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onGoNext(ActionEvent ev)
{
int index = list.getSelectedIndex()+1;
if(index >= 0 && index < list.getModel().getSize())
{
list.setSelectedIndex(index);
onGoTo(null);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onGoPrev(ActionEvent ev)
{
int index = list.getSelectedIndex()-1;
if(index >= 0 && index < list.getModel().getSize())
{
list.setSelectedIndex(index);
onGoTo(null);
}
}
//}}}
//{{{ editViews
//##################################################################################################
/** Display the view-editing dialog box */
public void editViews()
{
// Fill the list
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
list.setListData( kin.getViewList().toArray() );
// Display dialog box
dialog.pack();
dialog.setLocationRelativeTo(kMain.getTopWindow());
dialog.setVisible(true);
// remember, execution of this thread stops here until dialog is closed
UIMenus menus = kMain.getMenus();
if(menus != null) menus.rebuildViewsMenu(kin.getViewIterator());
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/PrefsEditor.java 0000644 0000000 0000000 00000024245 11531212674 020052 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.data.*;
import driftwood.gui.*;
import driftwood.util.SoftLog;
//}}}
/**
* PrefsEditor
provides a GUI for editing preferences.
* Because the list of loaded plugins could change at any time,
* instances of this class should only be used once and then discarded.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Thu Dec 12 13:32:25 EST 2002
*/
public class PrefsEditor //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
JDialog dialog;
JTabbedPane tabPane;
JTextField fontMagnification, fontSizeSmall, fontSizeBig;
JTextField stereoAngle;
JCheckBox joglByDefault, textOpenOnStart;
JCheckBox treeConfirmDelete, treeConfirmMerge;
JCheckBox checkNewVersion;
Map pluginMenuMap; // maps plugin class name to a JComboBox
JButton btnDone, btnDefaults, btnSave;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public PrefsEditor(KingMain kmain)
{
kMain = kmain;
buildGUI();
}
//}}}
//{{{ buildGUI
//##################################################################################################
private void buildGUI()
{
btnDone = new JButton(new ReflectiveAction("Close", null, this, "onDone"));
btnDefaults = new JButton(new ReflectiveAction("Reset to defaults", null, this, "onDefaults"));
btnSave = new JButton(new ReflectiveAction("Save to disk", null, this, "onSave"));
if(kMain.getApplet() != null) btnSave.setEnabled(false);
Component generalPane = buildGeneralPane();
Component pluginPane = buildPluginsPane();
tabPane = new JTabbedPane();
tabPane.addTab("General", generalPane);
tabPane.addTab("Plugins", pluginPane);
TablePane2 content = new TablePane2();
content.hfill(true).vfill(true).addCell(tabPane, 2, 1);
content.newRow();
content.center().memorize();
content.addCell(btnDefaults).addCell(btnSave);
content.newRow();
content.addCell(btnDone, 2, 1);
dialog = new JDialog(kMain.getTopWindow(), "Configure KiNG", true);
dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
dialog.setContentPane(content);
}
//}}}
//{{{ buildGeneralPane
//##################################################################################################
private Component buildGeneralPane()
{
fontMagnification = new JTextField(4);
fontSizeSmall = new JTextField(4);
fontSizeBig = new JTextField(4);
stereoAngle = new JTextField(4);
joglByDefault = new JCheckBox("Start in OpenGL mode");
textOpenOnStart = new JCheckBox("Open text window on startup");
treeConfirmDelete = new JCheckBox("Ask before deleting groups");
treeConfirmMerge = new JCheckBox("Ask before merging groups");
checkNewVersion = new JCheckBox("Check for new version online");
TablePane2 innerPane = new TablePane2();
innerPane.addCell(new JLabel("Menu font magnification (requires restart)")).addCell(fontMagnification).newRow();
innerPane.addCell(new JLabel("Font size (normal)")).addCell(fontSizeSmall).newRow();
innerPane.addCell(new JLabel("Font size (large)")).addCell(fontSizeBig).newRow();
innerPane.addCell(new JLabel("Stereo angle (- cross, + wall)")).addCell(stereoAngle).newRow();
innerPane.addCell(joglByDefault, 2, 1).newRow();
innerPane.addCell(textOpenOnStart, 2, 1).newRow();
innerPane.addCell(treeConfirmDelete, 2, 1).newRow();
innerPane.addCell(treeConfirmMerge, 2, 1).newRow();
innerPane.addCell(checkNewVersion, 2, 1).newRow();
return innerPane;
}
//}}}
//{{{ buildPluginsPane
//##################################################################################################
private Component buildPluginsPane()
{
ToolBox toolbox = kMain.getCanvas().getToolBox();
Collection plugins = toolbox.getPluginList();
// Make a list of all unique submenu names
UberSet menuNames = new UberSet();
menuNames.add(ToolBox.MENU_NONE);
menuNames.add(ToolBox.MENU_MAIN);
menuNames.add(ToolBox.MENU_IMPORT);
menuNames.add(ToolBox.MENU_EXPORT);
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
menuNames.add(toolbox.getPluginMenuName((Plugin)iter.next()));
Object[] items = menuNames.toArray();
// Add GUI components for all plugins, one per row
pluginMenuMap = new HashMap();
TablePane2 content = new TablePane2();
content.addCell(new JLabel("Choose a menu for each tool, or type in a new menu name."), 3, 1).newRow();
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
{
Plugin p = (Plugin) iter.next();
JComboBox combo = new JComboBox(items);
combo.setSelectedItem(toolbox.getPluginMenuName(p));
combo.setEditable(true);
content.addCell(new JLabel(p.toString()));
content.addCell(content.strut(10,0));
content.hfill(true).addCell(combo);
content.newRow();
pluginMenuMap.put(p.getClass().getName(), combo);
}
JScrollPane scroll = new JScrollPane(content);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
// Keep the list from being too tall in the dialog
Dimension dim = scroll.getPreferredSize();
dim.height = 100;
scroll.setPreferredSize(dim);
return scroll;
}
//}}}
//{{{ edit, editPlugins
//##################################################################################################
public void edit()
{
toGUI();
dialog.pack();
dialog.setLocationRelativeTo(kMain.getTopWindow());
dialog.setVisible(true);
// remember, execution of this thread stops here until dialog is closed
}
public void editPlugins()
{
int index = tabPane.indexOfTab("Plugins");
if(index != -1)
tabPane.setSelectedIndex(index);
this.edit();
}
//}}}
//{{{ toGUI, fromGUI
//##################################################################################################
private void toGUI()
{
KingPrefs p = kMain.prefs;
if(p == null) return;
fontMagnification.setText(p.getString("fontMagnification"));
fontSizeSmall.setText(p.getString("fontSizeSmall"));
fontSizeBig.setText(p.getString("fontSizeBig"));
stereoAngle.setText(p.getString("stereoAngle"));
joglByDefault.setSelected(p.getBoolean("joglByDefault"));
textOpenOnStart.setSelected(p.getBoolean("textOpenOnStart"));
treeConfirmDelete.setSelected(p.getBoolean("treeConfirmDelete"));
treeConfirmMerge.setSelected(p.getBoolean("treeConfirmMerge"));
checkNewVersion.setSelected(p.getBoolean("checkNewVersion"));
}
private void fromGUI()
{
KingPrefs p = kMain.prefs;
if(p == null) return;
try {
Float f = new Float(fontMagnification.getText().trim());
p.setProperty("fontMagnification", f.toString());
} catch(NumberFormatException ex) {}
try {
Integer i = new Integer(fontSizeSmall.getText().trim());
p.setProperty("fontSizeSmall", i.toString());
} catch(NumberFormatException ex) {}
try {
Integer i = new Integer(fontSizeBig.getText().trim());
p.setProperty("fontSizeBig", i.toString());
} catch(NumberFormatException ex) {}
try {
Float f = new Float(stereoAngle.getText().trim());
p.setProperty("stereoAngle", f.toString());
} catch(NumberFormatException ex) {}
p.setProperty("joglByDefault", new Boolean(joglByDefault.isSelected()).toString());
p.setProperty("textOpenOnStart", new Boolean(textOpenOnStart.isSelected()).toString());
p.setProperty("treeConfirmDelete", new Boolean(treeConfirmDelete.isSelected()).toString());
p.setProperty("treeConfirmMerge", new Boolean(treeConfirmMerge.isSelected()).toString());
p.setProperty("checkNewVersion", new Boolean(checkNewVersion.isSelected()).toString());
for(Iterator iter = pluginMenuMap.keySet().iterator(); iter.hasNext(); )
{
String pluginName = (String) iter.next();
JComboBox combo = (JComboBox) pluginMenuMap.get(pluginName);
String menuName = (String) combo.getSelectedItem();
p.setProperty(pluginName+".menuName", menuName);
}
}
//}}}
//{{{ onDone, onSave, onDefaults
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDone(ActionEvent ev)
{
fromGUI();
dialog.setVisible(false);
kMain.notifyChange(KingMain.EM_PREFS);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onSave(ActionEvent ev)
{
fromGUI();
try { kMain.prefs.storeToFile(); }
catch(SecurityException ex) { ex.printStackTrace(SoftLog.err); }
toGUI();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDefaults(ActionEvent ev)
{
KingPrefs prefs = kMain.getPrefs();
prefs.clear();
toGUI();
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/KinStable.java 0000644 0000000 0000000 00000016045 11531212674 017477 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
/**
* KinStable
holds all of the data about one or more kin files.
* It acts as the root for the hierarchy of groups.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Wed Apr 24 11:22:51 EDT 2002
*/
public class KinStable implements ListSelectionListener
{
//{{{ Variables
KingMain kMain = null;
java.util.List children;
Kinemage currentKinemage = null; // the current kinemage within the file
volatile boolean isLocked = false;
JList kinChooser = null; // a list of all kinemages present in the stable
//}}}
//{{{ Constructor
//##################################################################################################
/**
* Constructor
*/
public KinStable(KingMain kmain)
{
kMain = kmain;
children = new ArrayList(10);
kinChooser = new JList(new DefaultListModel());
kinChooser.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
kinChooser.setVisibleRowCount(4);
kinChooser.setFixedCellWidth(100);
kinChooser.addListSelectionListener(this);
}
//}}}
//{{{ iterator, getKins
//##################################################################################################
/** Returns an iterator over the children of this element. All children will be Kinemages. */
public ListIterator iterator()
{ return children.listIterator(); }
/** Returns an unmodifiable list of all open kinemages. */
public java.util.List getKins()
{ return Collections.unmodifiableList(children); }
//}}}
//{{{ notifyChange
//##################################################################################################
// Called by KingMain when something happens.
// Shouldn't be called directly under normal circumstances.
void notifyChange(int event_mask)
{
// Take care of yourself
// Notify children
Kinemage kin = this.getKinemage();
KinCanvas canvas = kMain.getCanvas();
Engine engine = (canvas==null? null : canvas.getEngine());
if((event_mask & KingMain.EM_SWITCH) != 0
&& kin != null && engine != null)
{
canvas.getToolBox().services.doFlatland.setSelected(kin.atFlat);
engine.whiteBackground = kin.atWhitebackground;
engine.usePerspective = kin.atPerspective;
engine.colorByList = kin.atListcolordominant;
if(kin.atOnewidth)
{
engine.cueThickness = false;
engine.thinLines = false;
}
else if(kin.atThinline)
{
engine.cueThickness = false;
engine.thinLines = true;
}
else
{
//engine.cueThickness = true;
engine.thinLines = false;
}
UIMenus menus = kMain.getMenus();
if(menus != null) menus.displayMenu.syncCheckboxes();
// canvas will redraw itself in a moment, anyway...
}
}
//}}}
//{{{ closeAll, closeCurrent, append
//##################################################################################################
public void closeAll()
{
children.clear();
currentKinemage = null;
kMain.getTextWindow().setText("");
//kinChooser.removeAllItems(); // leaks memory!
// This leak is a bug in JComboBox.removeAllItems()
// as of v1.4.1 and has been reported to Sun by IWD.
// The following is a work-around:
kinChooser.setModel(new DefaultListModel());
kMain.notifyChange(kMain.EM_CLOSEALL);
}
public void closeCurrent()
{
children.remove(currentKinemage);
currentKinemage = null;
int selPos = kinChooser.getSelectedIndex();
Object selection = kinChooser.getSelectedValue();
DefaultListModel model = (DefaultListModel)kinChooser.getModel();
model.removeElement(selection);
selPos = Math.min(selPos, kinChooser.getModel().getSize() - 1);
if(selPos >= 0) kinChooser.setSelectedIndex(selPos);
kMain.notifyChange(kMain.EM_CLOSE);
}
/**
* Adds in the specified collection of kinemages.
* If there is no current kinemage, then the first of these becomes the current kinemage.
* @param kins a group of Kinemage objects to add (not null)
*/
public void append(Collection kins)
{
children.addAll(kins);
DefaultListModel model = (DefaultListModel)kinChooser.getModel();
Iterator iter = kins.iterator();
if(iter.hasNext())
{
currentKinemage = (Kinemage)iter.next();
currentKinemage.signal.subscribe(kMain);
model.addElement(currentKinemage);
kinChooser.setSelectedValue(currentKinemage, true);
}
while(iter.hasNext())
{
Kinemage k = (Kinemage)iter.next();
k.signal.subscribe(kMain);
model.addElement(k);
}
/**
* This if statement corrects for a bug(?) in java 1.5
* which was causing king to not select a kinemage if one
* was opened using the menu and there were no prior open
* kins.
**/
if(kinChooser.getSelectedIndex()==-1){
kinChooser.setSelectedIndex(0);
}
kMain.notifyChange(kMain.EM_SWITCH);
}
///}}}
//{{{ valueChanged, setLocked
//##################################################################################################
/* Gets called when a new kinemage is picked from the list (kinChooser) */
public void valueChanged(ListSelectionEvent ev)
{
currentKinemage = (Kinemage)kinChooser.getSelectedValue();
kMain.notifyChange(kMain.EM_SWITCH);
}
/** Used to control access to kinemage during file loading */
public synchronized void setLocked(boolean l)
{
if(isLocked != l)
{
isLocked = l;
kMain.notifyChange(kMain.EM_SWITCH);
}
}
//}}}
//{{{ getKinemage, getChooser, changeCurrentKinemage
//##################################################################################################
/** Returns the Kingemage that contains all of the 3-D data being displayed. */
public synchronized Kinemage getKinemage()
{
if(isLocked) return null;
else return currentKinemage;
}
/** Returns a JList that lists all the loaded kinemages. */
public Component getChooser() { return kinChooser; }
public void changeCurrentKinemage(int kinNum)
{
int i = 1;
for(Iterator iter = this.iterator(); iter.hasNext(); i++)
{
Kinemage kin = (Kinemage) iter.next();
if(i == kinNum)
kinChooser.setSelectedValue(kin, true);
}
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/EDMapWindow.java 0000644 0000000 0000000 00000035071 11531212674 017741 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
import driftwood.isosurface.*;
import driftwood.r3.*;
import driftwood.util.SoftLog;
//}}}
/**
* EDMapWindow
has controls for one
* electron density map, contoured at two levels.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Wed Mar 5 09:00:11 EST 2003
*/
public class EDMapWindow implements ChangeListener, ActionListener, TransformSignalSubscriber
{
//{{{ Constants
DecimalFormat df1 = new DecimalFormat("0.0");
//}}}
//{{{ Variable definitions
//##################################################################################################
protected KingMain kMain;
protected KinCanvas kCanvas;
ToolBox parent;
CrystalVertexSource map;
MarchingCubes mc1, mc2;
EDMapPlotter plotter1, plotter2;
String title;
protected JDialog dialog;
JSlider extent, slider1, slider2;
JCheckBox label1, label2;
JComboBox color1, color2;
JCheckBox useTriangles, useLowRes;
JButton discard, export;
float ctrX, ctrY, ctrZ;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public EDMapWindow(ToolBox parent, CrystalVertexSource map, String title)
{
this.parent = parent;
kMain = parent.kMain;
kCanvas = parent.kCanvas;
parent.sigTransform.subscribe(this);
this.map = map;
this.title = title;
ctrX = ctrY = ctrZ = Float.NaN;
// Plotters need to be non-null for signalTransform()
// These are never used though; overwritten on first updateMesh()
Object mode = MarchingCubes.MODE_TRIANGLE;
plotter1 = new EDMapPlotter(false, mode);
plotter2 = new EDMapPlotter(false, mode);
//mc1 = new MarchingCubes(map, map, plotter1, mode);
//mc2 = new MarchingCubes(map, map, plotter2, mode);
buildGUI();
dialog.pack();
dialog.setLocationRelativeTo(kMain.getTopWindow());
dialog.setVisible(true);
}
//}}}
//{{{ buildGUI
//##################################################################################################
void buildGUI()
{
dialog = new JDialog(kMain.getTopWindow(), title+" - EDMap", false);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
label1 = new JCheckBox("1.2 sigma", true);
label2 = new JCheckBox("3.0 sigma", false);
color1 = new JComboBox(kMain.getKinemage().getAllPaintMap().values().toArray());
color1.setSelectedItem(KPalette.gray);
color2 = new JComboBox(kMain.getKinemage().getAllPaintMap().values().toArray());
color2.setSelectedItem(KPalette.purple);
extent = new JSlider(0, 30, 10);
extent.setMajorTickSpacing(10);
extent.setMinorTickSpacing(2);
extent.setPaintTicks(true);
//extent.setSnapToTicks(true); -- this seems to be buggy/weird
extent.setPaintLabels(true);
slider1 = new JSlider(-80, 80, 12);
slider1.setMajorTickSpacing(10);
slider1.setPaintTicks(true);
//slider1.setSnapToTicks(true); -- this seems to be buggy/weird
slider1.setPaintLabels(false);
slider2 = new JSlider(-80, 80, 30);
slider2.setMajorTickSpacing(10);
slider2.setPaintTicks(true);
//slider2.setSnapToTicks(true); -- this seems to be buggy/weird
slider2.setPaintLabels(false);
useTriangles = new JCheckBox(new ReflectiveAction("Translucent surface", null, this, "onTriangles"));
useTriangles.setToolTipText("Enables a translucent triangle-mesh surface; use with Best rendering quality.");
useLowRes = new JCheckBox(new ReflectiveAction("Coarser mesh", null, this, "onCoarseMesh"));
discard = new JButton(new ReflectiveAction("Discard this map", null, this, "onMapDiscard"));
export = new JButton(new ReflectiveAction("Export to kinemage", null, this, "onMapExport"));
label1.addActionListener(this);
label2.addActionListener(this);
color1.addActionListener(this);
color2.addActionListener(this);
extent.addChangeListener(this);
slider1.addChangeListener(this);
slider2.addChangeListener(this);
TablePane pane = new TablePane();
pane.save().hfill(true).addCell(extent, 2, 1).restore();
pane.newRow();
pane.add(pane.strut(0,8));
pane.newRow();
pane.add(label1);
pane.add(color1);
pane.newRow();
pane.save().hfill(true).addCell(slider1, 2, 1).restore();
pane.newRow();
pane.add(pane.strut(0,4));
pane.newRow();
pane.add(label2);
pane.add(color2);
pane.newRow();
pane.save().hfill(true).addCell(slider2, 2, 1).restore();
pane.newRow();
pane.add(pane.strut(0,4));
pane.newRow();
pane.add(useTriangles, 2, 1);
pane.newRow();
pane.add(useLowRes, 2, 1);
pane.newRow();
pane.center().hfill(true);
pane.add(export, 2, 1);
pane.newRow();
pane.add(discard, 2, 1);
dialog.setContentPane(pane);
JMenuBar menubar = new JMenuBar();
JMenu menu;
JMenuItem item;
menu = new JMenu("Presets");
menu.setMnemonic(KeyEvent.VK_P);
menubar.add(menu);
item = new JMenuItem(new ReflectiveAction("2Fo - Fc", null, this, "on2FoFc"));
item.setMnemonic(KeyEvent.VK_2);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, UIMenus.MENU_ACCEL_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Fo - Fc", null, this, "onFoFc"));
item.setMnemonic(KeyEvent.VK_1);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, UIMenus.MENU_ACCEL_MASK));
menu.add(item);
dialog.setJMenuBar(menubar);
}
//}}}
//{{{ stateChanged, actionPerformed, onTriangles, calcSliderValue
//##################################################################################################
public void stateChanged(ChangeEvent ev)
{
double val;
val = calcSliderValue(slider1);
label1.setText(df1.format(val)+" sigma");
val = calcSliderValue(slider2);
label2.setText(df1.format(val)+" sigma");
if(!extent.getValueIsAdjusting()
&& !slider1.getValueIsAdjusting()
&& !slider2.getValueIsAdjusting())
{
updateMesh();
kCanvas.repaint();
}
}
public void actionPerformed(ActionEvent ev)
{
kCanvas.repaint();
}
// target of reflection
public void onTriangles(ActionEvent ev)
{
updateMesh();
kCanvas.repaint();
}
// target of reflection
public void onCoarseMesh(ActionEvent ev)
{
updateMesh();
kCanvas.repaint();
}
double calcSliderValue(JSlider slider)
{
int i = slider.getValue();
if(-60 <= i && i <= 60)
return i/10.0;
else if(i > 60)
return (6.0 + (i-60)*2.0);
else if(i < -60)
return -(6.0 + (-i-60)*2.0);
else
throw new Error("assertion failure");
}
//}}}
//{{{ centerChanged
//##################################################################################################
/**
* Reports on whether the viewing center has been changed.
* Has the side effect of updating the internal center to match the current view.
*/
protected boolean centerChanged()
{
KingView v = kMain.getView();
if(v == null) return false;
float[] ctr = v.getCenter();
boolean ret = (ctrX != ctr[0] || ctrY != ctr[1] || ctrZ != ctr[2]);
ctrX = ctr[0];
ctrY = ctr[1];
ctrZ = ctr[2];
return ret;
}
//}}}
//{{{ updateMesh
//##################################################################################################
protected void updateMesh()
{
if(Float.isNaN(ctrX) || Float.isNaN(ctrY) || Float.isNaN(ctrZ)) return;
// Regenerate our plotting apparatus here in case the user's
// preference for std. mesh vs. cobwebs has changed.
Object mode = (useTriangles.isSelected() ? MarchingCubes.MODE_TRIANGLE : MarchingCubes.MODE_MESH);
plotter1 = new EDMapPlotter(false, mode);
plotter2 = new EDMapPlotter(false, mode);
double val, size = extent.getValue() / 2.0;
int[] corner1 = new int[3], corner2 = new int[3];
if(useLowRes.isSelected())
{
LowResolutionVertexSource lores = new LowResolutionVertexSource(map, 2);
mc1 = new MarchingCubes(lores, lores, plotter1, mode);
mc2 = new MarchingCubes(lores, lores, plotter2, mode);
lores.findVertexForPoint(ctrX-size, ctrY-size, ctrZ-size, corner1);
lores.findVertexForPoint(ctrX+size, ctrY+size, ctrZ+size, corner2);
}
else
{
mc1 = new MarchingCubes(map, map, plotter1, mode);
mc2 = new MarchingCubes(map, map, plotter2, mode);
map.findVertexForPoint(ctrX-size, ctrY-size, ctrZ-size, corner1);
map.findVertexForPoint(ctrX+size, ctrY+size, ctrZ+size, corner2);
}
/*double[] xyz = new double[3];
map.locateVertex(corner1[0], corner1[1], corner1[2], xyz);
SoftLog.err.println("findVertex("+(ctrX-size)+" "+(ctrY-size)+" " +(ctrZ-size)+") -> "+xyz[0]+" "+xyz[1]+" "+xyz[2]);
map.locateVertex(corner2[0], corner2[1], corner2[2], xyz);
SoftLog.err.println("findVertex("+(ctrX+size)+" "+(ctrY+size)+" " +(ctrZ+size)+") -> "+xyz[0]+" "+xyz[1]+" "+xyz[2]);*/
val = calcSliderValue(slider1);
mc1.march(corner1[0], corner1[1], corner1[2], corner2[0], corner2[1], corner2[2], val*map.sigma);
val = calcSliderValue(slider2);
mc2.march(corner1[0], corner1[1], corner1[2], corner2[0], corner2[1], corner2[2], val*map.sigma);
//SoftLog.err.println("Updated mesh: "+corner1[0]+" "+corner1[1]+" "+corner1[2]+" / "+corner2[0]+" "+corner2[1]+" "+corner2[2]);
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
KList list;
if(centerChanged()) updateMesh();
list = plotter1.getList();
if(list != null && label1.isSelected())
{
list.setColor((KPaint)color1.getSelectedItem());
list.signalTransform(engine, xform);
}
list = plotter2.getList();
if(list != null && label2.isSelected())
{
list.setColor((KPaint)color2.getSelectedItem());
list.signalTransform(engine, xform);
}
//SoftLog.err.println("Painted maps.");
}
//}}}
//{{{ on2FoFc, onFoFc
//##################################################################################################
// Preset values for 2Fo-Fc maps
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void on2FoFc(ActionEvent ev)
{
slider1.setValue(12); // +1.2
slider2.setValue(30); // +3.0
color1.setSelectedItem(KPalette.gray);
color2.setSelectedItem(KPalette.purple);
updateMesh();
kCanvas.repaint();
}
// Preset values for Fo-Fc (difference) maps
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFoFc(ActionEvent ev)
{
slider1.setValue(-35); // -3.5
slider2.setValue( 35); // +3.5
color1.setSelectedItem(KPalette.orange);
color2.setSelectedItem(KPalette.sky);
label1.setSelected(true);
label2.setSelected(true);
updateMesh();
kCanvas.repaint();
}
//}}}
//{{{ onMapDiscard, onMapExport
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onMapDiscard(ActionEvent ev)
{
dialog.dispose();
parent.sigTransform.unsubscribe(this);
kCanvas.repaint();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onMapExport(ActionEvent ev)
{
// insert lists into kinemage
Kinemage kin = kMain.getKinemage();
KGroup group = new KGroup(kin, "ED map");
kin.add(group);
kin.setModified(true);
KSubgroup subgroup = new KSubgroup(group, "ED map");
subgroup.setHasButton(false);
group.add(subgroup);
KList list1, list2;
list1 = plotter1.getList(); plotter1.freeList();
list2 = plotter2.getList(); plotter2.freeList();
if(list1 != null && label1.isSelected())
{
list1.setOwner(subgroup);
subgroup.add(list1);
}
if(list2 != null && label2.isSelected())
{
list2.setOwner(subgroup);
subgroup.add(list2);
}
updateMesh(); // regenerate the meshes we just exported
kMain.notifyChange(KingMain.EM_EDIT_GROSS | KingMain.EM_ON_OFF);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/KinfileLoader.java 0000644 0000000 0000000 00000010343 11531212674 020326 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
//import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
import java.util.zip.*;
//import java.util.regex.*;
import javax.swing.*;
//import driftwood.*;
//}}}
/**
* KinfileLoader
is a system for loading
* kinemages in a background thread. It messages a
* KinLoadListener with the results of its actions.
* This is the level where auto-detection of gzipped
* kinemages takes place.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Fri Apr 11 10:07:14 EDT 2003
*/
public class KinfileLoader implements ActionListener
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
InputStream input;
KinLoadListener listener;
Thread thread;
javax.swing.Timer timer;
KinfileParser parser;
Throwable thrown = null;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Creates a loader with the given input and listener,
* starts the job in the background, and returns as soon
* as the job has begun.
*/
public KinfileLoader(KingMain kmain, InputStream input, KinLoadListener listener)
{
this.kMain = kmain;
this.input = input;
this.listener = listener;
parser = new KinfileParser();
timer = new javax.swing.Timer(1000, this); // update every 1000ms
thread = new Thread(new ReflectiveRunnable(this, "backgroundWorker"));
thread.setDaemon(true);
timer.start();
thread.start();
}
//}}}
//{{{ backgroundWorker
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
/** Should not be called directly. Does loading in the background. */
public void backgroundWorker()
{
try
{
LineNumberReader lnr;
// Test for GZIPped files
input = new BufferedInputStream(input);
input.mark(10);
if(input.read() == 31 && input.read() == 139)
{
// We've found the gzip magic numbers...
input.reset();
input = new GZIPInputStream(input);
}
else input.reset();
lnr = new LineNumberReader(new InputStreamReader(input));
parser.parse(lnr);
SwingUtilities.invokeLater(new ReflectiveRunnable(this, "successCallback"));
lnr.close();
}
catch(Throwable t)
{
thrown = t;
SwingUtilities.invokeLater(new ReflectiveRunnable(this, "errorCallback"));
}
}
//}}}
//{{{ actionPerformed
//##################################################################################################
/** Messaged when the progress needs to be updated */
public void actionPerformed(ActionEvent ev)
{
listener.updateProgress(parser.getCharsRead());
}
//}}}
//{{{ successCallback, errorCallback
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
/** Should not be called directly. Notifies listener that kinemage has been loaded. */
public void successCallback()
{
timer.stop();
listener.loadingComplete(parser);
parser = null;
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
/** Should not be called directly. Notifies listener of I/O or other error. */
public void errorCallback()
{
timer.stop();
listener.loadingException(thrown);
parser = null;
thrown = null;
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/MageHypertextListener.java 0000644 0000000 0000000 00000001753 11531212674 022117 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
//import driftwood.*;
//}}}
/**
* MageHypertextListener
is able to get events when the user
* selects a Mage-style *{hyperlink}* from the text window.
*
* @see UIText#addHypertextListener(MageHypertextListener)
* @see UIText#removeHypertextListener(MageHypertextListener)
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Fri Jul 16 11:47:37 EDT 2004
*/
public interface MageHypertextListener //extends ... implements ...
{
/**
* Called by UIText whenever the user selects any Mage-style
* hyperlink, which is bracked by *{ and *}.
* @param link the text of the link, minus the flanking brackets
*/
public void mageHypertextHit(String link);
}//class
king-2.21.120420/king/1.x_src/king/MageHypertexter.java 0000644 0000000 0000000 00000007376 11531212674 020747 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.util.SoftLog;
//}}}
public class MageHypertexter implements MageHypertextListener
{
//{{{ Static fields
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Constructor
*/
public MageHypertexter(KingMain kmain) {
this.kMain = kmain;
}
//}}}
//{{{ mageHypertextHit
//##################################################################################################
public void mageHypertextHit(String link)
{
try
{
KinfileTokenizer token = new KinfileTokenizer(new LineNumberReader(new StringReader(link)));
while(!token.isEOF())
{
//if(!(token.isLiteral() || token.isProperty())) continue;
String cmd = token.getString().toLowerCase();
token.advance();
if(cmd.equals("kinemage") || cmd.equals("kin")) doKinToken(token);
else if(cmd.equals("view") || cmd.equals("v=")) doViewToken(token);
else if(cmd.startsWith("master") || cmd.equals("m=")) doMasterToken(token);
else if(cmd.equals("alloff")) doAllOffToken();
//else SoftLog.err.println("Unexpected hypertext token: "+cmd);
}
}
catch(IOException ex) {}
}
//}}}
//{{{ doKinToken, doViewToken
//##################################################################################################
public void doKinToken(KinfileTokenizer token) throws IOException
{
if(token.isInteger())
{
kMain.getStable().changeCurrentKinemage(token.getInt());
token.advance();
}
}
public void doViewToken(KinfileTokenizer token) throws IOException
{
if(token.isInteger())
{
try
{
Kinemage kin = kMain.getStable().getKinemage();
KingView view = (KingView)kin.getViewList().get(token.getInt() - 1);
kin.notifyViewSelected(view);
}
catch(IndexOutOfBoundsException ex) {}
token.advance();
}
}
//}}}
//{{{ doMasterToken, doAllOffToken
//##################################################################################################
public void doMasterToken(KinfileTokenizer token) throws IOException
{
if(token.isIdentifier())
{
String masterName = token.getString();
token.advance();
if(token.isLiteral())
{
String masterAlive = token.getString().toLowerCase();
token.advance();
Kinemage kin = kMain.getKinemage();
if(masterAlive.equals("on")) kin.getMasterByName(masterName).setOn(true);
else if(masterAlive.equals("off")) kin.getMasterByName(masterName).setOn(false);
kMain.notifyChange(KingMain.EM_ON_OFF);
}
}
}
public void doAllOffToken() {
Kinemage kin = kMain.getKinemage();
Collection masters = kin.masterList();
Iterator iter = masters.iterator();
while (iter.hasNext()) {
MasterGroup master = (MasterGroup) iter.next();
master.setOn(false);
}
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/KinCanvas.java 0000644 0000000 0000000 00000042163 11531212674 017500 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.print.*;
//import java.io.*;
import java.lang.reflect.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
import driftwood.r3.*;
import driftwood.util.*;
//}}}
/**
* KinCanvas
is the display surface for the 3-D model.
*
*
Begun on Mon Apr 22 17:19:48 EDT 2002
*
Copyright (C) 2002-2003 by Ian W. Davis. All rights reserved.
*/
public class KinCanvas extends JComponent implements TransformSignalSubscriber, ChangeListener, Printable
{
//{{{ Static fields
static final double LOG_2 = Math.log(2.0);
static final int SLIDER_SCALE = 16;
public static final int QUALITY_GOOD = 0;
public static final int QUALITY_BETTER = 1;
public static final int QUALITY_BEST = 2;
public static final int QUALITY_JOGL = 10;
//}}}
//{{{ Variables
//##################################################################################################
KingMain kMain = null;
Engine engine = null;
ToolBox toolbox = null;
StandardPainter goodPainter = new StandardPainter(false);
StandardPainter betterPainter = new StandardPainter(true);
HighQualityPainter bestPainter = new HighQualityPainter(true);
Component joglCanvas = null;
ReflectiveAction joglAction = null;
DefaultBoundedRangeModel zoommodel = null;
DefaultBoundedRangeModel clipmodel = null;
Image logo = null;
int renderQuality = QUALITY_GOOD;
boolean writeFPS;
//}}}
//{{{ Constructor
//##################################################################################################
/**
* Creates a new drawing surface that displays the given set of visible lists.
*
* @param kmain the program instance that owns this canvas
*/
public KinCanvas(KingMain kmain)
{
super();
kMain = kmain;
// Set default graphics mode for OS X
// This partly compensates for broken graphics primitives
// on Mac implementations through at least 1.4.1...
try
{
String os = System.getProperty("os.name").toLowerCase();
if(os.indexOf("mac") != -1 || os.indexOf("apple") != -1)
renderQuality = QUALITY_BETTER;
}
catch(SecurityException ex) { SoftLog.err.println(ex.getMessage()); }
// Determine the screen size:
Rectangle screenBounds =
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds();
int screenSize = (3*Math.min(screenBounds.width, screenBounds.height)) / 4;
Props props = kMain.getPrefs();
Dimension canvasSize = new Dimension(screenSize, screenSize);
Dimension minCanvasSize = new Dimension(200, 200);
if(props.hasProperty("graphicsWidth" ) && props.getInt("graphicsWidth") >= minCanvasSize.width)
canvasSize.width = props.getInt("graphicsWidth");
if(props.hasProperty("graphicsHeight") && props.getInt("graphicsHeight") >= minCanvasSize.height)
canvasSize.height = props.getInt("graphicsHeight");
writeFPS = props.getBoolean("writeFPS", false);
// This will be overriden in KingMain if we're a
// webpage-embedded applet
setPreferredSize(canvasSize);
setMinimumSize(minCanvasSize);
setOpaque(true);
zoommodel = new DefaultBoundedRangeModel(0, 0, -3*SLIDER_SCALE, 7*SLIDER_SCALE);
zoommodel.addChangeListener(this);
clipmodel = new DefaultBoundedRangeModel(200, 0, 0, 800);
clipmodel.addChangeListener(this);
engine = new Engine();
engine.updatePrefs(kMain.prefs); // set font sizes etc
logo = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("images/king-logo.gif"));
// We do this to enable mouse wheel in Java 1.4 without
// causing a NoClassDefFoundError in Java 1.3.
// For ToolBoxMW to not be loaded automatically,
// there must not be any "hard" references to it from
// main(). Thus, we use reflection instead.
// A similar approach is used for XML.
if(System.getProperty("java.version").compareTo("1.4") >= 0)
{
try
{
// What I'd like to do:
//ToolBoxMW toolboxmw = new ToolBoxMW(kMain, this);
//addMouseWheelListener(toolboxmw);
//toolbox = toolboxmw;
// Create a ToolBoxMW instance
Class mwClass = Class.forName("king.ToolBoxMW");
Constructor mwConstr = mwClass.getConstructor(new Class[] { KingMain.class, KinCanvas.class });
toolbox = (ToolBox)mwConstr.newInstance(new Object[] { kMain, this });
}
catch(Throwable t)
{
t.printStackTrace(SoftLog.err);
toolbox = new ToolBox(kMain, this);
}
}
else
{
toolbox = new ToolBox(kMain, this);
}
toolbox.listenTo(this);
// If we do this here, everything JOGL needs is already created. I think.
// It seems to work, at least, which isn't true if this code comes earlier!
if(kMain.getPrefs().getBoolean("joglByDefault"))
{
try
{
//SoftLog.err.println("Trying to init OpenGL...");
//this.setQuality(QUALITY_JOGL); -- generates an error dialog
this.loadJOGL();
this.renderQuality = QUALITY_JOGL;
}
catch(Throwable t) {}//{ t.printStackTrace(SoftLog.err); }
}
}
//}}}
//{{{ notifyChange, shutdown
//##################################################################################################
// Called by KingMain when something happens.
// Shouldn't be called directly under normal circumstances.
void notifyChange(int event_mask)
{
// Notify children
if(engine != null)
{
if((event_mask & KingMain.EM_PREFS) != 0)
engine.updatePrefs(kMain.prefs);
if((event_mask & (KingMain.EM_CLOSE|KingMain.EM_CLOSEALL)) != 0)
engine.flushZBuffer(); // prevents memory leaks
}
if(toolbox != null) toolbox.notifyChange(event_mask);
// Take care of yourself
if(event_mask != 0) this.repaint();
KingView view = kMain.getView();
if(view != null && (event_mask & (KingMain.EM_NEWVIEW | KingMain.EM_SWITCH)) != 0)
{
double viewspan = view.getSpan();
double kinspan = kMain.getKinemage().getSpan();
zoommodel.setValue((int)Math.round((double)SLIDER_SCALE * Math.log(kinspan/viewspan) / LOG_2));
clipmodel.setValue((int)(view.getClip() * 200.0));
}
}
void shutdown()
{
}
//}}}
//{{{ painting
//##################################################################################################
/** Override of JPanel.paintComponent -- wrapper for paintCanvas. */
protected void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
paintCanvas(g2, this.getSize(), renderQuality);
}
/** Does the rendering, with Engine.render() doing most of the real work. */
public void paintCanvas(Graphics2D g2, Dimension dim, int quality)
{
/* A quick query for analyzing graphics performance
java.awt.image.VolatileImage vi = createVolatileImage(getWidth(), getHeight());
if(vi != null)
{
ImageCapabilities ic = vi.getCapabilities();
SoftLog.err.println("isAccelerated = "+ic.isAccelerated()+"; isTrueVolatile = "+ic.isTrueVolatile());
}*/
Kinemage kin = kMain.getKinemage();
if(kin == null)
{
g2.setColor(Color.black);
g2.fillRect(0, 0, dim.width, dim.height);
if(logo != null) g2.drawImage(logo, (dim.width-logo.getWidth(this))/2, (dim.height-logo.getHeight(this))/2, this);
if(kMain.getPrefs().newerVersionAvailable())
announceNewVersion(g2);
}
// This is not the usual way in which the JOGL canvas is redrawn,
// and in fact, it may NEVER get called any more because the actual
// KinCanvas object is never displayed while the JOGL canvas is.
else if(quality >= QUALITY_JOGL && joglAction != null)
joglAction.actionPerformed(null);
else
{
Painter painter = null;
if(quality == QUALITY_BETTER)
{
betterPainter.setGraphics(g2);
painter = betterPainter;
}
else if(quality == QUALITY_BEST)
{
bestPainter.setGraphics(g2);
painter = bestPainter;
}
else //(quality == QUALITY_GOOD)
{
goodPainter.setGraphics(g2);
painter = goodPainter;
}
long timestamp = System.currentTimeMillis();
KingView view = kin.getCurrentView();
Rectangle bounds = new Rectangle(dim);
engine.syncToKin(kin);
engine.render(this, view, bounds, painter);
if(toolbox != null) toolbox.overpaintCanvas(painter);
timestamp = System.currentTimeMillis() - timestamp;
if(writeFPS)
SoftLog.err.println(timestamp+" ms ("+(timestamp > 0 ? Long.toString(1000/timestamp) : ">1000")
+" FPS) - "+engine.getNumberPainted()+" objects painted");
}
}
//}}}
//{{{ announceNewVersion
//##################################################################################################
void announceNewVersion(Graphics2D g2)
{
String msg = "A new version of KiNG is now available";
Dimension d = this.getSize();
Font font = new Font("SansSerif", Font.BOLD, 16);
g2.setFont(font);
g2.setColor(Color.white);
FontMetrics metrics = g2.getFontMetrics();
Rectangle2D r = metrics.getStringBounds(msg, g2);
g2.drawString(msg, (d.width - (int)r.getWidth())/2, (d.height - (int)r.getHeight())/2 + 170);
}
//}}}
//{{{ printing
//##################################################################################################
/**
* Printer callback -- calls KingRenderingEngine to do the real work.
* This code was copied directly from paintComponent
*/
public int print(Graphics g, PageFormat format, int pageindex)
{
Graphics2D g2 = (Graphics2D)g;
Dimension dim = getCanvasSize();
Kinemage kin = kMain.getKinemage();
if(kin == null || pageindex > 0) return NO_SUCH_PAGE;
else
{
KingView view = kin.getCurrentView();
// Scale the paper to match the graphics window:
double scale = Math.min( (double)(format.getImageableWidth() / dim.width),
(double)(format.getImageableHeight()/dim.height) );
g2.scale(scale, scale);
g2.setClip((int)(format.getImageableX()/scale), (int)(format.getImageableY()/scale), dim.width, dim.height);
Rectangle bounds = new Rectangle(dim);
bounds.setLocation((int)(format.getImageableX()/scale), (int)(format.getImageableY()/scale));
engine.syncToKin(kin);
bestPainter.setGraphics(g2);
engine.render(this, view, bounds, bestPainter);
if(toolbox != null) toolbox.overpaintCanvas(bestPainter);
return PAGE_EXISTS;
}
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signalTransform(engine, xform);
if(toolbox != null) toolbox.signalTransform(engine, xform);
}
//}}}
//{{{ get/set functions
//##################################################################################################
public BoundedRangeModel getZoomModel() { return zoommodel; }
public BoundedRangeModel getClipModel() { return clipmodel; }
/** Returns a button that arms the pick-center function */
public Component getPickcenterButton() { return toolbox.services.doPickcenter; }
/** Returns a button that shows markers */
public Component getMarkersButton() { return toolbox.services.doMarkers; }
/** The size of the drawing surface (!= this.getSize() in OpenGL mode) */
public Dimension getCanvasSize()
{ return engine.getCanvasSize(); };
/** Returns the drawing engine this canvas uses for rendering. */
public Engine getEngine() { return engine; }
/** Returns the toolbox used for interacting with this canvas. */
public ToolBox getToolBox() { return toolbox; }
/** Sets the rendering quality to one of the QUALITY_XXX constants */
public void setQuality(int q)
{
renderQuality = q;
// JOGL canvas is reusable in some situations but not others:
// eg it crashes on FC2 with Java 1.5. For some reason, we must set the
// graphics component here -- it doesn't work in paintComponent()!
if(q == QUALITY_JOGL)// && joglCanvas == null)
{
try { loadJOGL(); }
catch(Throwable t)
{
t.printStackTrace(SoftLog.err);
joglCanvas = null;
joglAction = null;
JOptionPane.showMessageDialog(kMain.getTopWindow(),
"Unable to initialize OpenGL graphics.\nSee user manual for details on enabling this feature.",
"No OpenGL", JOptionPane.ERROR_MESSAGE);
}
}
else if(q < QUALITY_JOGL)
kMain.getContentPane().setGraphicsComponent(this);
}
//}}}
//{{{ stateChanged
//##################################################################################################
public void stateChanged(ChangeEvent ev)
{
KingView view = kMain.getView();
if(view == null) return;
if(ev.getSource() == zoommodel)
{
double kinspan = kMain.getKinemage().getSpan();
double newspan = kinspan / Math.pow(2, (double)zoommodel.getValue() / (double)SLIDER_SCALE);
view.setSpan((float)newspan);
this.repaint();
}
else if(ev.getSource() == clipmodel)
{
double newclip = (double)clipmodel.getValue() / 200.0;
view.setClip((float)newclip);
this.repaint();
}
}
//}}}
//{{{ isFocusTraversable()
//##################################################################################################
// Has been replaced with isFocusable() in 1.4+
public boolean isFocusTraversable()
{ return true; }
public boolean isFocusable()
{ return true; }
//}}}
//{{{ repaint, loadJOGL
//##################################################################################################
/** To ensure OpenGL painting is done even when the canvas is hidden. */
public void repaint()
{
super.repaint();
if(renderQuality >= QUALITY_JOGL && joglAction != null)
{
// Is this check really needed?
if(kMain.getContentPane().getGraphicsComponent() != joglCanvas)
kMain.getContentPane().setGraphicsComponent(joglCanvas);
joglAction.actionPerformed(null);
}
}
// lazily loads the JOGL Painter just before we need it
private void loadJOGL() throws Throwable
{
// Try to create a JOGL painter, via reflection
Class joglClass = Class.forName("king.JoglCanvas");
Constructor joglConstr = joglClass.getConstructor(new Class[] { KingMain.class, Engine.class, ToolBox.class });
joglCanvas = (Component)joglConstr.newInstance(new Object[] { kMain, engine, toolbox });
joglAction = new ReflectiveAction(null, null, joglCanvas, "requestRepaint");
}
//}}}
//{{{ empty
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/PointEditor.java 0000644 0000000 0000000 00000034267 11531212674 020071 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.net.*;
//import java.text.*;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
//}}}
/**
* PointEditor
allows editing of point properties,
* for single points and for groups of points.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Fri Dec 13 08:34:44 EST 2002
*/
public class PointEditor implements ChangeListener
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
GroupEditor groupEditor;
JDialog ptDialog;
JTextField ptID, ptComment, ptAspects, ptMasters, ptWidthRadius, ptX, ptY, ptZ;
ColorPicker ptPicker;
JCheckBox ptUnpickable;
JLabel ptIndex;
JButton split;
boolean ptFirstShow = true;
KPoint thePoint = null;
KPaint ptOrigColor = null;
int index = 0; //index of this point in the KList
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public PointEditor(KingMain kmain)
{
kMain = kmain;
groupEditor = new GroupEditor(kMain, kMain.getTopWindow());
makePointDialog();
}
//}}}
//{{{ makePointDialog
//##################################################################################################
private void makePointDialog()
{
ptDialog = new JDialog(kMain.getTopWindow(), "Edit point", true);
ptDialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
ptID = new JTextField(20);
ptComment = new JTextField(20);
ptAspects = new JTextField(8);
ptMasters = new JTextField(8);
ptWidthRadius = new JTextField(8);
ptX = new JTextField(8);
ptY = new JTextField(8);
ptZ = new JTextField(8);
ptUnpickable = new JCheckBox("Unpickable");
ptIndex = new JLabel("Index is x/xxx");
KingPrefs prefs = kMain.getPrefs();
int patchSize = (prefs==null? 20 : prefs.getInt("colorSwatchSize"));
ptPicker = new ColorPicker(KPaint.BLACK_COLOR, patchSize);
ptPicker.addChangeListener(this);
split = new JButton(new ReflectiveAction("Split list before this", null, this, "onPointSplit"));
JButton ok = new JButton(new ReflectiveAction("OK", null, this, "onPointOK"));
JButton cancel = new JButton(new ReflectiveAction("Cancel", null, this, "onPointCancel"));
JButton editGroup = new JButton(new ReflectiveAction("Edit group", null, this, "onEditGroup"));
JButton editSubgroup = new JButton(new ReflectiveAction("Edit subgroup", null, this, "onEditSubgroup"));
JButton editList = new JButton(new ReflectiveAction("Edit list", null, this, "onEditList"));
TablePane tp = new TablePane();
//tp.insets(4);
tp.hfill(true);
tp.startSubtable();
tp.add(new JLabel("Point ID"));
tp.add(ptID, 3, 1);
tp.newRow();//----------
tp.add(new JLabel("Comment"));
tp.add(ptComment, 3, 1);
tp.newRow();//----------
tp.skip();
tp.add(ptUnpickable);
tp.add(ptPicker, 1, 10);
tp.newRow();//----------
tp.add(new JLabel("Aspects"));
tp.add(ptAspects);
tp.newRow();//----------
tp.add(new JLabel("Pointmasters"));
tp.add(ptMasters);
tp.newRow();//----------
tp.add(new JLabel("Width/Radius"));
tp.add(ptWidthRadius);
tp.newRow();//----------
tp.skip();
tp.add(new JLabel("0 => from list"));
tp.newRow();//----------
tp.add(new JLabel("X coord"));
tp.add(ptX);
tp.newRow();//----------
tp.add(new JLabel("Y coord"));
tp.add(ptY);
tp.newRow();//----------
tp.add(new JLabel("Z coord"));
tp.add(ptZ);
tp.newRow();//----------
tp.add(ptIndex);
tp.center().add(split);
tp.newRow();//----------
tp.add(Box.createVerticalGlue(), 2, 1); // allows for extra height of color picker
tp.endSubtable();
tp.newRow();//----------
tp.skip();
tp.newRow();//----------
tp.startSubtable();
tp.center();
tp.add(editList);
tp.add(editSubgroup);
tp.add(editGroup);
tp.endSubtable();
tp.newRow();//----------
tp.add(tp.strut(0,4));
tp.newRow();//----------
tp.startSubtable();
tp.center();
tp.add(ok);
tp.add(cancel);
tp.endSubtable();
ptDialog.setContentPane(tp);
}
//}}}
//{{{ editPoint
//##################################################################################################
public void editPoint(KPoint p)
{
if(p == null) return;
KList list = (KList)p.getOwner(); if(list == null) return;
Kinemage kin = p.getKinemage(); if(kin == null) return;
thePoint = p;
// Write values to GUI
ptID.setText(p.getName());
String comment = p.getComment();
if(comment == null) ptComment.setText("");
else ptComment.setText(comment);
ptAspects.setText(p.getAspects());
ptMasters.setText(kin.fromPmBitmask(p.getPmMask()));
ptX.setText(Float.toString(p.getOrigX()));
ptY.setText(Float.toString(p.getOrigY()));
ptZ.setText(Float.toString(p.getOrigZ()));
ptUnpickable.setSelected(p.isUnpickable());
// Color
ptOrigColor = p.getColor();
ptPicker.setBackgroundMode(kMain.getCanvas().getEngine().backgroundMode);
ptPicker.setExtras(kMain.getKinemage().getNewPaintMap().values());
ptPicker.setSelection(ptOrigColor);
// Width / Radius
if(p instanceof VectorPoint)
{
ptWidthRadius.setEnabled(true);
ptWidthRadius.setText(Integer.toString(p.getWidth()));
}
else if(p instanceof BallPoint)
{
ptWidthRadius.setEnabled(true);
ptWidthRadius.setText(Float.toString(((BallPoint)p).r0));
}
else
{
ptWidthRadius.setEnabled(false);
ptWidthRadius.setText("n/a");
}
// Index
int size;
index = 0;
Iterator iter = list.iterator();
for(size = 0; iter.hasNext(); size++)
{
// KPoint.equals() just compares coordinates.
if(p == iter.next()) index = size;
}
ptIndex.setText("Index is "+(index+1)+"/"+size);
if(index == 0) split.setEnabled(false);
else split.setEnabled(true);
ptDialog.pack();
if(ptFirstShow) { ptDialog.setLocationRelativeTo(kMain.getTopWindow()); ptFirstShow = false; }
ptDialog.setVisible(true);
// thread stops here until we hit OK/Cancel
}
//}}}
//{{{ onPointOK, onPointCancel, onPointColor
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onPointOK(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
thePoint.setName(ptID.getText());
String comment = ptComment.getText().trim();
if(comment.length() == 0) thePoint.setComment(null);
else thePoint.setComment(comment);
String aspects = ptAspects.getText().trim().toUpperCase();
if(aspects.length() > 0) thePoint.setAspects(aspects);
else thePoint.setAspects(null);
if(kin != null) thePoint.setPmMask(kin.toPmBitmask(ptMasters.getText().trim(), true, true));
thePoint.setUnpickable(ptUnpickable.isSelected());
try { thePoint.setOrigX(Float.parseFloat(ptX.getText().trim())); }
catch(NumberFormatException ex) {}
try { thePoint.setOrigY(Float.parseFloat(ptY.getText().trim())); }
catch(NumberFormatException ex) {}
try { thePoint.setOrigZ(Float.parseFloat(ptZ.getText().trim())); }
catch(NumberFormatException ex) {}
// Let "" be the same as zero here
if(ptWidthRadius.getText().trim().equals("")) ptWidthRadius.setText("0");
try {
if(thePoint instanceof VectorPoint)
{
int w = Integer.parseInt(ptWidthRadius.getText().trim());
if(w > 7) w = 7;
if(w < 0) w = 0;
thePoint.setWidth(w);
}
else if(thePoint instanceof BallPoint)
{
float r = Float.parseFloat(ptWidthRadius.getText().trim());
((BallPoint)thePoint).r0 = r;
}
} catch(NumberFormatException ex) {}
ptDialog.dispose();
thePoint = null; // avoid memory leaks
if(kin != null) kin.setModified(true);
kMain.notifyChange(KingMain.EM_EDIT_FINE);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onPointCancel(ActionEvent ev)
{
thePoint.setColor(ptOrigColor);
ptDialog.dispose();
thePoint = null; // avoid memory leaks
}
public void stateChanged(ChangeEvent ev)
{
Kinemage kin = thePoint.getKinemage();
if(kin == null) return;
thePoint.setColor(ptPicker.getSelection());
kMain.notifyChange(KingMain.EM_EDIT_FINE);
}
//}}}
//{{{ onPointSplit
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onPointSplit(ActionEvent ev)
{
KList origlist = (KList)thePoint.getOwner(); if(origlist == null) return;
KSubgroup subgroup = (KSubgroup)origlist.getOwner(); if(subgroup == null) return;
java.util.List allkids = origlist.children;
if(index < 1 || index >= allkids.size()) return;
KList newlist = new KList(subgroup, origlist.getName());
subgroup.add(newlist);
newlist.type = origlist.type;
newlist.color = origlist.color;
newlist.radius = origlist.radius;
newlist.width = origlist.width;
newlist.flags = origlist.flags;
newlist.masters = new ArrayList(origlist.masters);
newlist.setOn(origlist.isOn());
newlist.setHasButton(origlist.hasButton());
//newlist.setDominant(origlist.isDominant());
origlist.children = new ArrayList( allkids.subList(0,index) );
newlist.children = new ArrayList( allkids.subList(index,allkids.size()) );
for(Iterator iter = newlist.iterator(); iter.hasNext(); )
{ ((KPoint)iter.next()).setOwner(newlist); }
// We may need to duplicate this point to avoid breaks in the list
if(thePoint.getPrev() != null)
{
if(thePoint instanceof VectorPoint)
{
VectorPoint prev , origvp, newvp;
origvp = (VectorPoint)thePoint;
prev = (VectorPoint)origvp.getPrev();
newvp = new VectorPoint(origlist, origvp.getName(), prev);
newvp.setOrigX(origvp.getOrigX());
newvp.setOrigY(origvp.getOrigY());
newvp.setOrigZ(origvp.getOrigZ());
newvp.setAspects(origvp.getAspects());
newvp.setPmMask(origvp.getPmMask());
newvp.multi = origvp.multi;
newvp.setWidth(origvp.getWidth());
origlist.add(newvp);
origvp.setPrev(null);
}
else if(thePoint instanceof TrianglePoint)
{
TrianglePoint prev , origtp, newtp;
origtp = (TrianglePoint)thePoint;
prev = (TrianglePoint)origtp.getPrev();
newtp = new TrianglePoint(origlist, origtp.getName(), prev);
newtp.setOrigX(origtp.getOrigX());
newtp.setOrigY(origtp.getOrigY());
newtp.setOrigZ(origtp.getOrigZ());
newtp.setAspects(origtp.getAspects());
newtp.setPmMask(origtp.getPmMask());
newtp.multi = origtp.multi;
origlist.add(newtp);
origtp.setPrev(null);
}
}
Kinemage k = kMain.getKinemage();
if(k != null) k.setModified(true);
kMain.notifyChange(KingMain.EM_EDIT_GROSS | KingMain.EM_EDIT_FINE);
}
//}}}
//{{{ onEditGroup, onEditSubgroup, onEditList
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditGroup(ActionEvent ev)
{
KList list = (KList)thePoint.getOwner(); if(list == null) return;
KSubgroup subgroup = (KSubgroup)list.getOwner(); if(subgroup == null) return;
KGroup group = (KGroup)subgroup.getOwner(); if(group == null) return;
if(groupEditor.editGroup(group)) kMain.notifyChange(KingMain.EM_EDIT_GROSS);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditSubgroup(ActionEvent ev)
{
KList list = (KList)thePoint.getOwner(); if(list == null) return;
KSubgroup subgroup = (KSubgroup)list.getOwner(); if(subgroup == null) return;
if(groupEditor.editSubgroup(subgroup)) kMain.notifyChange(KingMain.EM_EDIT_GROSS);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditList(ActionEvent ev)
{
KList list = (KList)thePoint.getOwner(); if(list == null) return;
if(groupEditor.editList(list)) kMain.notifyChange(KingMain.EM_EDIT_GROSS);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/UIMenus.java 0000644 0000000 0000000 00000100530 11531212674 017141 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import driftwood.gui.*;
import driftwood.util.SoftLog;
//}}}
/**
* UIMenus
contains all the menus and their corresponding
* Action objects for various actions the user can take.
*
*
Begun on Sat Apr 27 20:34:46 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*/
public class UIMenus //extends ... implements ...
{
static final DecimalFormat df = new DecimalFormat("###,###,##0");
public static /*final*/ int MENU_ACCEL_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
//{{{ Variable definitions
//##################################################################################################
KingMain kMain;
JMenuBar menubar;
UIDisplayMenu displayMenu;
// Tool-like objects
JFileChooser fileChooser = null;
SuffixFileFilter fileFilter;
PointFinder finder;
ViewEditor viewEditor;
// Elements of menus that get rebuilt frequently
JMenu oldViewMenu = null;
JMenu fileMenu, toolsMenu;
//}}}
//{{{ Constructor, getMenuBar()
//##################################################################################################
public UIMenus(KingMain kmain)
{
kMain = kmain;
// CTRL-x shortcuts are still useful in a Mac browser.
// There's no good option for Windows / Linux broswers though.
if(kMain.getApplet() != null) MENU_ACCEL_MASK = Event.CTRL_MASK;
// Will throw an exception if we're running as an Applet
try
{
fileFilter = new SuffixFileFilter("Kinemage files (*.kin)");
fileFilter.addSuffix(".kin");
fileFilter.addSuffix(".kip");
fileFilter.addSuffix(".kip1");
fileFilter.addSuffix(".kip2");
fileFilter.addSuffix(".kip3");
fileFilter.addSuffix(".kip4");
fileFilter.addSuffix(".kip5");
fileFilter.addSuffix(".kip6");
fileFilter.addSuffix(".kip7");
fileFilter.addSuffix(".kip8");
fileFilter.addSuffix(".kip9");
fileChooser = new JFileChooser();
String currdir = System.getProperty("user.dir");
if(currdir != null) fileChooser.setCurrentDirectory(new File(currdir));
fileChooser.addChoosableFileFilter(fileFilter);
fileChooser.setFileFilter(fileFilter);
}
catch(SecurityException ex) {}
finder = new PointFinder(kMain);
viewEditor = new ViewEditor(kMain);
buildMenus();
}
/** Returns the menu bar */
public JMenuBar getMenuBar() { return menubar; }
//}}}
//{{{ buildMenus()
//##################################################################################################
// Construct all the menus and their actions for the menubar.
void buildMenus()
{
menubar = new JMenuBar();
JMenu menu, submenu;
JMenuItem item;
JCheckBoxMenuItem cbitem;
KinCanvas kCanvas;
// File menu
fileMenu = menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menubar.add(menu);
rebuildFileMenu();
//{{{ Edit menu
menu = new JMenu("Edit");
menu.setMnemonic(KeyEvent.VK_E);
menubar.add(menu);
item = new JMenuItem(new ReflectiveAction("Find point...", null, this, "onEditFind"));
item.setMnemonic(KeyEvent.VK_F);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, MENU_ACCEL_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Find next", null, this, "onEditFindNext"));
item.setMnemonic(KeyEvent.VK_N);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, MENU_ACCEL_MASK));
menu.add(item);
menu.addSeparator();
item = new JMenuItem(new ReflectiveAction("Kinemage properties...", null, this, "onEditKinProps"));
item.setMnemonic(KeyEvent.VK_K);
//item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, MENU_ACCEL_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Edit text...", null, this, "onEditText"));
item.setMnemonic(KeyEvent.VK_T);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, MENU_ACCEL_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Edit hierarchy...", null, this, "onEditHierarchy"));
item.setMnemonic(KeyEvent.VK_H);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, MENU_ACCEL_MASK));
menu.add(item);
menu.addSeparator();
item = new JMenuItem(new ReflectiveAction("Configure KiNG...", null, this, "onEditConfigure"));
item.setMnemonic(KeyEvent.VK_C);
menu.add(item);
//}}}
// Views menu
rebuildViewsMenu(null);
// Display menu
displayMenu = new UIDisplayMenu(kMain);
menubar.add(displayMenu.getMenu());
// Tools menu
toolsMenu = menu = new JMenu("Tools");
menu.setMnemonic(KeyEvent.VK_T);
menubar.add(menu);
rebuildToolsMenu();
//{{{ Help menu
menu = new JMenu("Help");
menu.setMnemonic(KeyEvent.VK_H);
menubar.add(menu);
item = new JMenuItem(new ReflectiveAction("User manual...", null, this, "onHelpManual"));
item.setMnemonic(KeyEvent.VK_M);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); // 0 => no modifiers
menu.add(item);
submenu = new JMenu("Tools");
submenu.setMnemonic(KeyEvent.VK_T);
menu.add(submenu);
kCanvas = kMain.getCanvas();
if(kCanvas != null)
{
ToolBox tb = kCanvas.getToolBox();
if(tb != null)
tb.addPluginsToHelpMenu(submenu);
}
item = new JMenuItem(new ReflectiveAction("Keyboard shortcuts...", null, this, "onHelpKeyboardShortcuts"));
item.setMnemonic(KeyEvent.VK_S);
//item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); // 0 => no modifiers
menu.add(item);
submenu = new JMenu("Built-in kinemages");
submenu.setMnemonic(KeyEvent.VK_K);
menu.add(submenu);
item = new JMenuItem(new ReflectiveAction("Internal palette", null, this, "onHelpKinPalette"));
item.setMnemonic(KeyEvent.VK_P);
submenu.add(item);
item = new JMenuItem(new ReflectiveAction("Color cone", null, this, "onHelpKinCone"));
item.setMnemonic(KeyEvent.VK_C);
submenu.add(item);
item = new JMenuItem(new ReflectiveAction("Falling teddy bear", null, this, "onHelpKinBear"));
item.setMnemonic(KeyEvent.VK_B);
submenu.add(item);
item = new JMenuItem(new ReflectiveAction("Error log...", null, this, "onHelpLog"));
item.setMnemonic(KeyEvent.VK_E);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, MENU_ACCEL_MASK)); // 0 => no modifiers
menu.add(item);
item = new JMenuItem(new ReflectiveAction("About KiNG...", null, this, "onHelpAbout"));
item.setMnemonic(KeyEvent.VK_A);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K, MENU_ACCEL_MASK)); // 0 => no modifiers
menu.add(item);
//}}}
}
//}}}
//{{{ rebuildFileMenu
//##################################################################################################
public void rebuildFileMenu()
{
JMenuItem item;
JMenu menu = fileMenu;
menu.removeAll();
JApplet applet = kMain.getApplet();
if(applet == null) // => not in an applet
{
item = new JMenuItem(new ReflectiveAction("New KiNG window", null, this, "onFileNewKing"));
item.setMnemonic(KeyEvent.VK_N);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, MENU_ACCEL_MASK));
menu.add(item);
menu.addSeparator();
}
item = new JMenuItem(new ReflectiveAction("Open...", null, this, "onFileOpen"));
item.setMnemonic(KeyEvent.VK_O);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, MENU_ACCEL_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Append...", null, this, "onFileMerge"));
item.setMnemonic(KeyEvent.VK_A);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, MENU_ACCEL_MASK));
menu.add(item);
if(applet == null) // not in an applet
{
KinCanvas kCanvas = kMain.getCanvas();
if(kCanvas != null)
{
ToolBox tb = kCanvas.getToolBox();
if(tb != null)
{
JMenu importMenu = new JMenu("Import");
importMenu.setMnemonic(KeyEvent.VK_I);
tb.addPluginsToSpecialMenu(ToolBox.MENU_IMPORT, importMenu);
if(importMenu.getItemCount() > 0)
{
menu.add(importMenu);
}
}
}
}
item = new JMenuItem(new ReflectiveAction("Close", null, this, "onFileClose"));
item.setMnemonic(KeyEvent.VK_C);
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Close all", null, this, "onFileCloseAll"));
item.setMnemonic(KeyEvent.VK_L);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, MENU_ACCEL_MASK));
menu.add(item);
menu.addSeparator();
if(applet == null || applet.getParameter("kinfileSaveHandler") != null)
{
item = new JMenuItem(new ReflectiveAction("Save as...", null, this, "onFileSaveAs"));
item.setMnemonic(KeyEvent.VK_S);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, MENU_ACCEL_MASK));
menu.add(item);
}
if(applet == null) // => not in an applet
{
KinCanvas kCanvas = kMain.getCanvas();
if(kCanvas != null)
{
ToolBox tb = kCanvas.getToolBox();
if(tb != null)
{
JMenu exportMenu = new JMenu("Export");
exportMenu.setMnemonic(KeyEvent.VK_E);
tb.addPluginsToSpecialMenu(ToolBox.MENU_EXPORT, exportMenu);
if(exportMenu.getItemCount() > 0)
{
menu.add(exportMenu);
}
}
}
}
// This might throw a SecurityException, if the user denies us permission...
item = new JMenuItem(new ReflectiveAction("Print...", null, this, "onFilePrint"));
item.setMnemonic(KeyEvent.VK_P);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, MENU_ACCEL_MASK));
menu.add(item);
if(applet == null) // => not in an applet
{
menu.addSeparator();
item = new JMenuItem(new ReflectiveAction("Exit", null, this, "onFileExit"));
item.setMnemonic(KeyEvent.VK_X);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, MENU_ACCEL_MASK));
menu.add(item);
}
}
//}}}
//{{{ rebuildViewsMenu
//##################################################################################################
/**
* Creates a new Views menu from the specified iterator of KingView objects
* @param viewiter Iterator of KingViews, or null for an empty menu
*/
public void rebuildViewsMenu(Iterator viewiter)
{
JMenu menu = new JMenu("Views");
menu.setMnemonic(KeyEvent.VK_V);
JMenuItem item;
JRadioButtonMenuItem ritem;
ButtonGroup rgroup = new ButtonGroup();
if(viewiter != null)
{
item = new JMenuItem(new ReflectiveAction("Save current view", null, this, "onViewSave"));
item.setMnemonic(KeyEvent.VK_S);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, MENU_ACCEL_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Edit saved views...", null, this, "onViewEdit"));
item.setMnemonic(KeyEvent.VK_E);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, MENU_ACCEL_MASK | KeyEvent.SHIFT_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Choose viewing axes...", null, this, "onViewChooseAxes"));
item.setMnemonic(KeyEvent.VK_C);
//item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, MENU_ACCEL_MASK | KeyEvent.SHIFT_MASK));
menu.add(item);
item = new JMenuItem(new ReflectiveAction("Parallel coordinates", null, this, "onViewParallelCoords"));
item.setMnemonic(KeyEvent.VK_P);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, 0));
menu.add(item);
menu.addSeparator();
JMenu currMenu = menu;
for(int i = 1; viewiter.hasNext(); i++)
{
// Every 25 views, chain them into a new menu
if(i != 1 && i % 25 == 1)
{
JMenu newMenu = new JMenu("More views");
currMenu.add(newMenu);
currMenu = newMenu;
}
KingView view = (KingView)viewiter.next();
ritem = new JRadioButtonMenuItem(new ReflectiveAction((i+" "+view.toString()), null, view, "selectedFromMenu"));
rgroup.add(ritem);
currMenu.add(ritem);
}
}
else
{
item = new JMenuItem("No views available");
item.setEnabled(false);
menu.add(item);
}
if(oldViewMenu != null)
{
int viewIndex = menubar.getComponentIndex(oldViewMenu);
menubar.remove(oldViewMenu);
menubar.add(menu, viewIndex);
}
else
{
menubar.add(menu);
}
// This step is ESSENTIAL for the menu to appear & keep working!
menubar.revalidate();
oldViewMenu = menu;
}
//}}}
//{{{ rebuildToolsMenu
//##################################################################################################
public void rebuildToolsMenu()
{
JMenuItem item;
JCheckBoxMenuItem cbitem;
JMenu menu = toolsMenu;
menu.removeAll();
cbitem = kMain.getCanvas().getToolBox().services.doFlatland;
cbitem.setMnemonic(KeyEvent.VK_L);
cbitem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, 0));
menu.add(cbitem);
cbitem = kMain.getCanvas().getToolBox().services.doXYZ;
cbitem.setMnemonic(KeyEvent.VK_X);
//cbitem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, MENU_ACCEL_MASK));
menu.add(cbitem);
cbitem = kMain.getCanvas().getToolBox().services.doMeasureAll;
cbitem.setMnemonic(KeyEvent.VK_M);
cbitem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0));
menu.add(cbitem);
cbitem = kMain.getCanvas().getToolBox().services.doObjectPick;
cbitem.setMnemonic(KeyEvent.VK_O);
menu.add(cbitem);
cbitem = kMain.getCanvas().getToolBox().services.doSuperpick;
cbitem.setMnemonic(KeyEvent.VK_S);
menu.add(cbitem);
KinCanvas kCanvas = kMain.getCanvas();
if(kCanvas != null)
{
ToolBox tb = kCanvas.getToolBox();
if(tb != null)
{
menu.addSeparator();
tb.addPluginsToToolsMenu(menu);
}
}
menu.addSeparator();
item = new JMenuItem(new ReflectiveAction("Customize Tools menu...", null, this, "onEditConfigurePlugins"));
item.setMnemonic(KeyEvent.VK_C);
menu.add(item);
}
//}}}
//{{{ reporter() -- the dummy action
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void reporter(ActionEvent ev)
{
JOptionPane.showMessageDialog(kMain.getTopWindow(), "This feature has not been implemented yet.", "Sorry!", JOptionPane.INFORMATION_MESSAGE);
}
//}}}
//{{{ onFileXXX handlers
//##################################################################################################
//### "File" functions #############################################################################
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileNewKing(ActionEvent ev)
{
new KingMain(new String[] {}).Main();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileOpen(ActionEvent ev)
{
KinfileIO io = kMain.getKinIO();
if(kMain.getApplet() != null) io.askLoadURL(null);
else io.askLoadFile(null);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileMerge(ActionEvent ev)
{
KinfileIO io = kMain.getKinIO();
Kinemage kin = kMain.getKinemage();
if(kin == null)
{
kin = new Kinemage(KinfileParser.DEFAULT_KINEMAGE_NAME+"1");
boolean success = false;
if(kMain.getApplet() != null) success = io.askLoadURL(kin);
else success = io.askLoadFile(kin);
if(success)
kMain.getStable().append(Arrays.asList(new Kinemage[] {kin}));
// This way we don't create an empty if append is canceled
}
else
{
if(kMain.getApplet() != null) io.askLoadURL(kin);
else io.askLoadFile(kin);
}
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileClose(ActionEvent ev)
{
Kinemage k = kMain.getKinemage();
if(k != null && k.isModified())
{
int confirm = JOptionPane.showConfirmDialog(kMain.getTopWindow(),
"This kinemage has been modified.\nDo you want to save it before closing?",
"Save before closing?", JOptionPane.YES_NO_CANCEL_OPTION);
if(confirm == JOptionPane.CANCEL_OPTION) return;
else if(confirm == JOptionPane.YES_OPTION) onFileSaveAs(ev);
}
kMain.getStable().closeCurrent();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileCloseAll(ActionEvent ev)
{
boolean modified = false;
for(Iterator iter = kMain.getStable().iterator(); iter.hasNext(); )
{
Kinemage k = (Kinemage) iter.next();
if(k.isModified()) modified = true;
}
if(modified)
{
int confirm = JOptionPane.showConfirmDialog(kMain.getTopWindow(),
"One or more open kinemages have been modified.\nDo you want to save them before closing?",
"Save before closing?", JOptionPane.YES_NO_CANCEL_OPTION);
if(confirm == JOptionPane.CANCEL_OPTION) return;
else if(confirm == JOptionPane.YES_OPTION) onFileSaveAs(ev);
}
kMain.getStable().closeAll();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileSaveAs(ActionEvent ev)
{
KinfileIO io = kMain.getKinIO();
if(kMain.getApplet() != null) io.askSaveURL();
else
{
int numKins = kMain.getStable().getKins().size();
if(numKins > 1)
{
JRadioButton btnBoth = new JRadioButton((numKins == 2 ? "Save both in one file" : "Save all "+numKins+" in one file"), true);
JRadioButton btnCurr = new JRadioButton("Save only the currently selected kinemage", false);
ButtonGroup btnGroup = new ButtonGroup();
btnGroup.add(btnBoth);
btnGroup.add(btnCurr);
int result = JOptionPane.showConfirmDialog(kMain.getTopWindow(),
new Object[] {
"There are currently "+numKins+" open kinemages.",
"What do you want to do?",
btnBoth,
btnCurr
},
"Saving multiple kinemages",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
if(result == JOptionPane.NO_OPTION || result == JOptionPane.CANCEL_OPTION) {}
else if(btnBoth.isSelected()) io.askSaveFile();
else if(btnCurr.isSelected()) io.askSaveFile(kMain.getKinemage());
}
else io.askSaveFile();
}
}
// This might throw a SecurityException, if the user denies us permission...
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFilePrint(ActionEvent ev)
{
try
{
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(kMain.getCanvas());
if(job.printDialog()) job.print();
}
catch(Exception ex) { ex.printStackTrace(SoftLog.err); }
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFileExit(ActionEvent ev)
{
onFileCloseAll(ev); // checks for modifications and prompts to save
if(kMain.getStable().getKins().size() == 0) kMain.shutdown();
// else we must have pressed Cancel
}
//}}}
//{{{ onEditXXX handlers
//##################################################################################################
//### "Edit" functions #############################################################################
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditFind(ActionEvent ev)
{
finder.show();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditFindNext(ActionEvent ev)
{
// If we can't find a next point, offer to search again.
if( finder.findNext() == false )
onEditFind(ev);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditText(ActionEvent ev)
{
UIText win = kMain.getTextWindow();
if(win != null) win.onPopupButton(null);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditKinProps(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
GroupEditor groupEd = new GroupEditor(kMain, kMain.getTopWindow());
groupEd.editKinemage(kin);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditHierarchy(ActionEvent ev)
{
KinTree win = kMain.getKinTree();
if(win != null) win.show();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditConfigure(ActionEvent ev)
{
PrefsEditor prefsEditor = new PrefsEditor(kMain);
prefsEditor.edit();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onEditConfigurePlugins(ActionEvent ev)
{
PrefsEditor prefsEditor = new PrefsEditor(kMain);
prefsEditor.editPlugins();
}
//}}}
//{{{ onViewXXX handlers
//##################################################################################################
//### "Views" functions ############################################################################
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onViewSave(ActionEvent ev)
{
String viewname = JOptionPane.showInputDialog(kMain.getTopWindow(),
"Name for this view:",
"Save view",
JOptionPane.PLAIN_MESSAGE);
if(viewname == null) return;
KingView view = kMain.getView();
if(view == null) return;
view = (KingView)view.clone();
view.setID(viewname);
// User should choose to save axes positions or not (?)
// If the data is high-D data, views only really make sense
// in the context of the dimensions that were being viewed!
//view.setViewingAxes(null);
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.addView(view);
kin.setModified(true);
rebuildViewsMenu(kin.getViewIterator());
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onViewEdit(ActionEvent ev)
{
viewEditor.editViews();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onViewChooseAxes(ActionEvent ev)
{
new AxisChooser(kMain, kMain.getKinemage());
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onViewParallelCoords(ActionEvent ev)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
String key = ParaParams.class.getName()+".instance";
ParaParams params = (ParaParams) kin.metadata.get(key);
if(params == null)
{
params = new ParaParams(kin);
kin.metadata.put(key, params);
}
params.swap();
kin.signal.signalKinemage(kin, KinemageSignal.STRUCTURE | KinemageSignal.APPEARANCE);
}
//}}}
//{{{ onHelpXXX handlers
//##################################################################################################
//### "Help" functions ############################################################################
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpManual(ActionEvent ev)
{
URL start = getClass().getResource("html/king-manual.html");
if(start != null) new HTMLHelp(kMain, start).show();
else SoftLog.err.println("Couldn't find the specified resource!");
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpKeyboardShortcuts(ActionEvent ev)
{
URL start = getClass().getResource("html/kbd-shortcuts.html");
if(start != null) new HTMLHelp(kMain, start).show();
else SoftLog.err.println("Couldn't find the specified resource!");
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpKinPalette(ActionEvent ev)
{
URL palkin = getClass().getResource("kins/pal5.kin");
if(palkin != null) kMain.getKinIO().loadURL(palkin, null);
else SoftLog.err.println("Couldn't find the specified resource!");
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpKinCone(ActionEvent ev)
{
URL kin = getClass().getResource("kins/cone.kin");
if(kin != null) kMain.getKinIO().loadURL(kin, null);
else SoftLog.err.println("Couldn't find the specified resource!");
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpKinBear(ActionEvent ev)
{
URL kin = getClass().getResource("kins/fallingbear.kin");
if(kin != null) kMain.getKinIO().loadURL(kin, null);
else SoftLog.err.println("Couldn't find the specified resource!");
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpLog(ActionEvent ev)
{
new LogViewer(kMain.getTopWindow(), "KiNG error log", SoftLog.err);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onHelpAbout(ActionEvent ev)
{
ArrayList msgs = new ArrayList();
KingPrefs prefs = kMain.getPrefs();
Runtime runtime = Runtime.getRuntime();
int i, total0 = 0, free0 = 0, total1 = 0, free1 = 0, used; // in kilobytes
msgs.add(new JLabel("KiNG (Kinetic Image, Next Generation)"));
msgs.add(new JLabel("Version "+kMain.getPrefs().getString("version")));
msgs.add(new JLabel("Build "+kMain.getPrefs().getString("buildnum")));
try {
if(prefs.jarFileDirectory != null)
msgs.add(new JLabel("Installed in "+prefs.jarFileDirectory.getCanonicalPath()));
} catch(IOException ex) {}
msgs.add(new JLabel(" "));
msgs.add(new JLabel("Created in the Richardson lab at Duke University"));
msgs.add(new JLabel("http://kinemage.biochem.duke.edu"));
msgs.add(new JLabel(" "));
msgs.add(new JLabel("Copyright (C) 2002-2005 Ian W. Davis and Vincent B. Chen"));
msgs.add(new JLabel("All rights reserved."));
msgs.add(new JLabel(" "));
msgs.add(new JLabel("Using Java "+System.getProperty("java.version", "(unknown version)")));
try {
msgs.add(new JLabel(System.getProperty("java.home", "(path not found)")));
} catch(SecurityException ex) {}
// We're not listing the versions of iText, JOGL, etc. here ...
//msgs.add(new JLabel("Using gnu.regexp "+gnu.regexp.RE.version()));
// Take up to 10 tries at garbage collection
for(i = 0; i < 10; i++)
{
total1 = (int)(runtime.totalMemory() >> 10);
free1 = (int)(runtime.freeMemory() >> 10);
if(total1 == total0 && free1 == free0) break;
else
{
System.gc();
//try { Thread.sleep(500); } catch(InterruptedException ex) {}
total0 = total1;
free0 = free1;
}
}
used = total1 - free1;
msgs.add(new JLabel(" "));
//msgs.add(new JLabel("Garbage collection freed "+df.format(free2-free1)+"kb"));
JProgressBar mem = new JProgressBar(0, total1);
mem.setStringPainted(true);
mem.setString(df.format(used)+"kb / "+df.format(total1)+"kb");
mem.setValue(used);
msgs.add(mem);
JOptionPane.showMessageDialog(kMain.getTopWindow(), msgs.toArray(), "About KiNG", JOptionPane.INFORMATION_MESSAGE);
}
/** I use this from JDB for tracking down memory leaks */
public static String showMem()
{
Runtime runtime = Runtime.getRuntime();
int i, total0 = 0, free0 = 0, total1 = 0, free1 = 0, used; // in kilobytes
// Take up to 10 tries at garbage collection
for(i = 0; i < 10; i++)
{
total1 = (int)(runtime.totalMemory() >> 10);
free1 = (int)(runtime.freeMemory() >> 10);
if(total1 == total0 && free1 == free0) break;
else
{
System.gc();
//try { Thread.sleep(500); } catch(InterruptedException ex) {}
total0 = total1;
free0 = free1;
}
}
used = total1 - free1;
return df.format(used)+"kb / "+df.format(total1)+"kb";
}
//}}}
//{{{ notifyChange
//##################################################################################################
// Called by KingMain when something happens.
// Shouldn't be called directly under normal circumstances.
static final int REDO_MENUS = KingMain.EM_SWITCH | KingMain.EM_CLOSE | KingMain.EM_CLOSEALL;
void notifyChange(int event_mask)
{
// Take care of yourself
if((event_mask & REDO_MENUS) != 0)
{
Kinemage kin = kMain.getKinemage();
if(kin != null)
{
rebuildViewsMenu(kin.getViewIterator());
}
else
{
rebuildViewsMenu(null);
}
displayMenu.rebuildAspectsMenu();
finder.clearSearch();
}
if((event_mask & KingMain.EM_PREFS) != 0)
{
// Plugin placement may have changed
rebuildFileMenu();
rebuildToolsMenu();
}
// Notify children
}
//}}}
}//class
king-2.21.120420/king/1.x_src/king/Kinglet.java 0000644 0000000 0000000 00000004441 11531212674 017215 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
//import java.text.*;
//import java.util.*;
import javax.swing.*;
//import driftwood.util.SoftLog;
//}}}
/**
* Kinglet
is the KiNG loader applet, to allow KiNG to be used in browsers.
*
*
Begun on Sun Jun 9 14:53:42 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*/
public class Kinglet extends JApplet implements MouseListener
{
public static final String NORMAL = "normal";
public static final String FLAT = "flat";
public static final String LAUNCHER = "launcher";
KingMain kMain = null;
String mode = null;
public void init()
{
String m = getParameter("mode");
if(m == null) mode = NORMAL;
else
{
m = m.toLowerCase();
if(m.equals("flat")) mode = FLAT;
else if(m.equals("launcher")) mode = LAUNCHER;
else mode = NORMAL;
}
if(mode.equals(NORMAL))
{
Icon kingletIcon = new ImageIcon(getClass().getResource("images/kinglet-logo.jpg"));
getContentPane().add(new JLabel(kingletIcon), BorderLayout.CENTER);
validate();
}
else if(mode.equals(LAUNCHER))
{
Icon kingletIcon = new ImageIcon(getClass().getResource("images/king-btn.png"));
getContentPane().add(new JLabel(kingletIcon), BorderLayout.CENTER);
addMouseListener(this);
validate();
}
}
public void start()
{ if(!mode.equals(LAUNCHER)) launch(); }
public void mouseClicked(MouseEvent ev)
{ launch(); }
void launch()
{
kMain = new KingMain(this, (mode.equals(FLAT)));
kMain.Main();
}
/** Initiates shutdown by calling dispose() on the windows. */
public void stop()
{
if(kMain != null) kMain.shutdown();
kMain = null; // so it can be GC'd
}
public void mouseEntered(MouseEvent ev) {}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
}//class
king-2.21.120420/king/1.x_src/king/MacDropTarget.java 0000644 0000000 0000000 00000005542 11531212674 020317 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import com.apple.eawt.*;
//import java.awt.*;
//import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
//import javax.swing.*;
import driftwood.util.SoftLog;
//}}}
/**
* MacDropTarget
provides drag-and-drop document opening
* under Mac OS X. This file will not compile on non-Mac platforms
* and should be removed (no other code depends on it).
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Fri Nov 7 09:41:14 EST 2003
*/
public class MacDropTarget implements ApplicationListener
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
static Application application = null;
KingMain kMain;
//}}}
//{{{ Constructor(s)
//##############################################################################
private MacDropTarget(KingMain kmain)
{
super();
kMain = kmain;
}
//}}}
//{{{ bindTo
//##############################################################################
static public void bindTo(KingMain kMain)
{
if(application == null)
application = new Application();
MacDropTarget drop = new MacDropTarget(kMain);
application.addApplicationListener(drop);
}
//}}}
//{{{ Unhandled events
//##############################################################################
public void handleAbout(ApplicationEvent e) {
}
public void handleOpenApplication(ApplicationEvent e) {
}
public void handleReOpenApplication(ApplicationEvent e) {
}
public void handlePreferences(ApplicationEvent e) {
}
public void handlePrintFile(ApplicationEvent e) {
}
//}}}
//{{{ handleOpenFile, handleQuit
//##############################################################################
public void handleOpenFile(ApplicationEvent ev)
{
//SoftLog.err.println("Received notification of file drop!");
KinfileIO io = kMain.getKinIO();
File f = new File(ev.getFilename());
if(f.exists())
{
io.loadFile(f, null);
ev.setHandled(true);
}
else SoftLog.err.println("Filename does not exist: '"+ev.getFilename()+"'");
}
public void handleQuit(ApplicationEvent ev)
{
// Necessary in order for Cmd-Q to work
ev.setHandled(true);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/ToolBox.java 0000644 0000000 0000000 00000064537 11531212674 017222 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
//import java.text.*;
import java.util.*;
import javax.swing.*;
import driftwood.gui.*;
import driftwood.r3.*;
import driftwood.util.*;
//}}}
/**
* ToolBox
instantiates and coordinates all the tools and plugins,
* using the Reflection API and a service provider (SPI) model,
* like the one in javax.imageio.ImageIO.scanForPlugins().
* We scan all jar files on the classpath for lists of Plugins that could be loaded by KiNG.
* We also scan all jar files in the folder named "plugins" that lives in the same
* place as king.jar, if such a folder exists.
* Plugins are listed in a plain text file META-INF/services/king.Plugin
* that's part of one or more JARs on the classpath.
* One fully-qualified class name is given per line, and nothing else.
*
*
Likewise, the submenu of Tools that a plugin belongs to, if any, is determined
* in the preferences file by the classname.menuName
property.
* The special values <main menu>
and <not shown>
* put the plugin in the main Tools menu or don't put in anywhere at all, respectively.
* KingPrefs scans all jars for files named king/king_prefs
,
* so plugins bundled in separate jars can include such a file to describe
* which menus they belong in.
*
*
Begun on Fri Jun 21 09:30:40 EDT 2002
*
Copyright (C) 2002-2004 by Ian W. Davis. All rights reserved.
*/
public class ToolBox implements MouseListener, MouseMotionListener, TransformSignalSubscriber
{
//{{{ Static fields
/** The menu name that will put a Plugin in the main menu rather than a submenu. */
static final String MENU_MAIN = "";
/** The menu name that will keep a Plugin out of the Tools menu entirely. */
static final String MENU_NONE = "";
/** The menu under File for importing non-kin files */
static final String MENU_IMPORT = "";
/** The menu under File for exporting non-kin files */
static final String MENU_EXPORT = "";
//}}}
//{{{ CLASS: PluginComparator, MenuComparator
//##################################################################################################
/** Sorts tools before plugins, then alphabetically by name. */
static class PluginComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
boolean tool1 = (o1 instanceof BasicTool);
boolean tool2 = (o2 instanceof BasicTool);
if(tool1 && !tool2) return -1;
else if(tool2 && !tool1) return 1;
else return o1.toString().compareTo(o2.toString());
}
}
/** Sorts JMenus alphabetically by name. */
static class MenuComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
JMenu m1 = (JMenu) o1;
JMenu m2 = (JMenu) o2;
return m1.getText().compareTo(m2.getText());
}
}
//}}}
//{{{ Variable definitions
//##################################################################################################
// These are public so tools in any package can access them.
public KingMain kMain;
public KinCanvas kCanvas;
public ToolServices services;
public TransformSignal sigTransform;
ArrayList plugins;
BasicTool activeTool;
final BasicTool defaultTool;
JMenuItem activeToolMI = null, defaultToolMI = null;
ClassLoader pluginClassLoader;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Constructor
*/
public ToolBox(KingMain kmain, KinCanvas kcanv)
{
// These are referenced by the tools
kMain = kmain;
kCanvas = kcanv;
services = new ToolServices(this);
sigTransform = new TransformSignal();
pluginClassLoader = this.makeClassLoader();
plugins = new ArrayList();
defaultTool = activeTool = new BasicTool(this);
plugins.add(activeTool);
loadPlugins();
activeTool.start();
}
//}}}
//{{{ makeClassLoader
//##################################################################################################
/**
* Creates a special class loader for loading plugins.
* If the named class cannot be found, it also searches the plugins/
* directory where king.jar is found or (for applets) the URL(s) named
* in the PLUGIN1, PLUGIN2, PLUGIN3, ... applet PARAMs.
*/
protected ClassLoader makeClassLoader()
{
ClassLoader defaultLoader = this.getClass().getClassLoader();
try
{
JApplet applet = kMain.getApplet();
ArrayList urls = new ArrayList();
// Case: we're running in an applet
if(applet != null)
{
/***************************************************************
* Throws an exception if we create a class loader...
*
java.security.AccessControlException: access denied (java.lang.RuntimePermission createClassLoader)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:269)
at java.security.AccessController.checkPermission(AccessController.java:401)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:524)
at java.lang.SecurityManager.checkCreateClassLoader(SecurityManager.java:586)
at java.lang.ClassLoader.(ClassLoader.java:186)
at java.security.SecureClassLoader.(SecureClassLoader.java:53)
at java.net.URLClassLoader.(URLClassLoader.java:81)
at king.ToolBox.makeClassLoader(ToolBox.java:169)
at king.ToolBox.(ToolBox.java:109)
// Numbering can start at 0 or 1, but must be continuous thereafter.
for(int i = 0; true; i++)
{
String relURL = applet.getParameter("plugin"+i);
if(relURL != null)
{
try { urls.add(new URL(applet.getDocumentBase(), relURL)); }
catch(MalformedURLException ex) { ex.printStackTrace(); }
}
else if(i >= 1) break; // out of for loop
}
***************************************************************/
}
// Case: we're running as a standalone application (NOT an applet)
else
{
File pluginFolder = new File(kMain.getPrefs().jarFileDirectory, "plugins");
if(!pluginFolder.exists() || !pluginFolder.canRead() || !pluginFolder.isDirectory())
return defaultLoader;
File[] files = pluginFolder.listFiles();
for(int i = 0; i < files.length; i++)
{
if(files[i].exists() && files[i].canRead() && files[i].isFile()
&& files[i].getName().toLowerCase().endsWith(".jar"))
{
try { urls.add(files[i].toURL()); }
catch(MalformedURLException ex) { SoftLog.err.println(ex.getMessage()); }
}
}
}
URLClassLoader jarLoader = new URLClassLoader(
(URL[]) urls.toArray(new URL[urls.size()]), defaultLoader);
return jarLoader;
}
catch(Exception ex) //IO, Security, MalformedURL, etc. etc.
{ ex.printStackTrace(SoftLog.err); }
return defaultLoader;
}
//}}}
//{{{ loadPlugins
//##################################################################################################
/**
* Automatically loads all the tools and plugins that are currently available
* to the system, while respecting their dependencies and applet safety.
*/
void loadPlugins()
{
// returned list might not be mutable, so make a copy
Collection toLoad = new ArrayList(scanForPlugins());
int oldSize;
do // cycle through all remaining names until no more can be loaded
{
oldSize = toLoad.size();
for(Iterator iter = toLoad.iterator(); iter.hasNext(); )
{
String name = (String) iter.next();
if(canLoadPlugin(name))
{
// Only try once, because we should succeed.
addPluginByName(name);
iter.remove();
}
}
}
while(oldSize > toLoad.size());
Collections.sort(plugins, new PluginComparator());
}
//}}}
//{{{ scanForPlugins
//##################################################################################################
/**
* Using a service-provider (SPI) model like the one in ImageIO.scanForPlugins(),
* we scan all jar files on the classpath for lists of Plugins that
* could be loaded by KiNG.
* Plugins are listed in a plain text file META-INF/services/king.Plugin
* that's part of one or more JARs on the classpath.
* @return a Collection<String> of fully-qualified plugin names.
*/
Collection scanForPlugins()
{
// This is how we load menu preferences for external plugins
try
{
// Write menu preferences into the defaults section of Prefs
Props pluginProps = (Props) kMain.getPrefs().getDefaults();
// No leading slashes when using this method
Enumeration urls = pluginClassLoader.getResources("king/king_prefs");
while(urls.hasMoreElements())
{
URL url = (URL) urls.nextElement();
try
{
InputStream is = url.openStream();
pluginProps.load(is);
is.close();
}
catch(IOException ex)
{ SoftLog.err.println("Plugin SPI error: "+ex.getMessage()); }
}
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
// Now load the actual list of plugins
Collection pluginNames = new ArrayList();
try
{
// No leading slashes when using this method
Enumeration urls = pluginClassLoader.getResources("META-INF/services/king.Plugin");
while(urls.hasMoreElements())
{
URL url = (URL) urls.nextElement();
try
{
LineNumberReader in = new LineNumberReader(new InputStreamReader(url.openStream()));
String s;
while((s = in.readLine()) != null)
{
s = s.trim();
if(!s.equals("") && !s.startsWith("#"))
pluginNames.add(s);
}
}
catch(IOException ex)
{ SoftLog.err.println("Plugin SPI error: "+ex.getMessage()); }
}
}
catch(IOException ex) { ex.printStackTrace(SoftLog.err); }
return pluginNames;
}
//}}}
//{{{ canLoadPlugin
//##################################################################################################
/**
* Returns true iff the following conditions are met:
* (1) the named class can be located and loaded
* (2) the plugin is applet-safe, or we're running as an application
* (3) all the plugins this one depends on are already loaded.
* @param className the fully qualified name of the Plugin class to check
*/
boolean canLoadPlugin(String className)
{
// Make a list of the full names of loaded plugins
Set loadedPlugins = new HashSet();
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
loadedPlugins.add(iter.next().getClass().getName());
try
{
Class pluginClass = Class.forName(className, true, pluginClassLoader);
Method appletSafe = pluginClass.getMethod("isAppletSafe", new Class[] {});
Boolean safe = (Boolean) appletSafe.invoke(null, new Object[] {});
if(kMain.getApplet() != null && safe.booleanValue() == false)
return false; // can't load because we're not applet safe
Method getDepend = pluginClass.getMethod("getDependencies", new Class[] {});
Collection deps = (Collection) getDepend.invoke(null, new Object[] {});
for(Iterator iter = deps.iterator(); iter.hasNext(); )
{
if(!loadedPlugins.contains(iter.next()))
return false; // can't load because of a dependency
}
return true; // can load; we've passed all the tests
}
catch(Throwable t)
{
t.printStackTrace(SoftLog.err);
return false; // can't load because of a reflection error
}
}
//}}}
//{{{ getPluginList, getPluginMenuName
//##################################################################################################
/** Returns an unmodifiable List of all installed plugins */
public java.util.List getPluginList()
{ return Collections.unmodifiableList(plugins); }
/** Returns the name of the menu the given Plugin belongs in right now */
public String getPluginMenuName(Plugin p)
{
// Read from user prefs + defaults
KingPrefs prefs = kMain.getPrefs();
String menuName = prefs.getString(p.getClass().getName()+".menuName", MENU_MAIN).trim();
if(menuName.equals("")) menuName = MENU_MAIN;
return menuName;
}
//}}}
//{{{ addPluginByName
//##################################################################################################
/**
* Tries to instantiate a plugin of the named class and insert it into the Toolbox,
* by using the Reflection API.
* @param name the fully qualified Java name of the plugin class, e.g. "king.BasicPlugin"
* @return true on success, false on failure
*/
private boolean addPluginByName(String name)
{
Plugin theplugin;
// First, check to see if we already have one.
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
{
theplugin = (Plugin)iter.next();
if(theplugin.getClass().getName().equals(name)) return true;
}
// If not, try to load one dynamically.
try
{
Class[] constargs = { ToolBox.class };
Object[] initargs = { this };
Class pluginclass = Class.forName(name, true, pluginClassLoader);
Constructor pluginconst = pluginclass.getConstructor(constargs);
theplugin = (Plugin)pluginconst.newInstance(initargs);
plugins.add(theplugin);
}
catch(Throwable t)
{
t.printStackTrace(SoftLog.err);
SoftLog.err.println("While trying to load '"+name+"': "+t.getMessage());
return false;
}
return true;
}
//}}}
//{{{ addPluginsToToolsMenu
//##################################################################################################
/** Appends menu items for using the loaded plugins */
public void addPluginsToToolsMenu(JMenu menu)
{
Plugin p;
JMenuItem item;
defaultToolMI = activeToolMI = null;
Map submenus = new HashMap(); // Map
ButtonGroup group = new ButtonGroup();
// Add things to primary menu and create submenus
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
{
p = (Plugin)iter.next();
item = p.getToolsMenuItem();
if(item != null)
{
String menuName = getPluginMenuName(p);
if(MENU_MAIN.equals(menuName)) menu.add(item);
else if(MENU_NONE.equals(menuName)) {} // don't add to any menu
else if(MENU_IMPORT.equals(menuName)) {} // don't add to any menu
else if(MENU_EXPORT.equals(menuName)) {} // don't add to any menu
else // add to the named submenu
{
JMenu submenu = (JMenu) submenus.get(menuName);
if(submenu == null)
{
submenu = new JMenu(menuName);
submenus.put(menuName, submenu);
}
submenu.add(item);
}
}
if(p instanceof BasicTool && item != null)
{
group.add(item);
if(p == defaultTool) defaultToolMI = item;
if(p == activeTool) activeToolMI = item;
}
}
// Sort the submenus alphabetically and add them at the end
ArrayList submenuList = new ArrayList(submenus.values());
Collections.sort(submenuList, new MenuComparator());
for(Iterator iter = submenuList.iterator(); iter.hasNext(); )
{
JMenu submenu = (JMenu) iter.next();
menu.add(submenu);
}
// Mark the active tool as such
if(activeToolMI != null) activeToolMI.setSelected(true);
}
//}}}
//{{{ addPluginsToHelpMenu
//##################################################################################################
/** Appends menu items for understanding the loaded plugins */
public void addPluginsToHelpMenu(JMenu menu)
{
Plugin p;
JMenuItem item;
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
{
p = (Plugin)iter.next();
item = p.getHelpMenuItem();
if(item != null) menu.add(item);
}
}
//}}}
//{{{ addPluginsToSpecialMenu
//##################################################################################################
/** Appends menu items for using the loaded plugins */
public void addPluginsToSpecialMenu(String whichMenu, JMenu menu)
{
Plugin p;
JMenuItem item;
for(Iterator iter = plugins.iterator(); iter.hasNext(); )
{
p = (Plugin)iter.next();
String menuName = getPluginMenuName(p);
if(whichMenu.equals(menuName))
{
item = p.getToolsMenuItem();
if(item != null) menu.add(item);
}
}
}
//}}}
//{{{ toolActivated, activateDefaultTool, notifyChange
//##################################################################################################
/** Called by Tools when their radio button gets hit. */
public void toolActivated(BasicTool t)
{
activeTool.stop();
//services.clearEverything();
activeTool = t;
activeTool.start();
}
/** Programmatically selects the Navigate tool. */
public void activateDefaultTool()
{
if(defaultToolMI != null)
defaultToolMI.setSelected(true);
toolActivated(defaultTool);
}
/**
* Called by KinCanvas when something happens.
* Shouldn't be called directly under normal circumstances.
*/
public void notifyChange(int event_mask)
{
int reset_tool = KingMain.EM_SWITCH | KingMain.EM_CLOSE | KingMain.EM_CLOSEALL;
if((event_mask & reset_tool) != 0)
{
services.clearEverything();
activeTool.reset();
}
}
//}}}
//{{{ listenTo
//##################################################################################################
/** Does all the work to make the ToolBox listen to the specified component. */
public void listenTo(Component c)
{
c.addMouseListener(this);
c.addMouseMotionListener(this);
if(c instanceof JComponent)
{
JComponent jc = (JComponent) c;
ActionMap am = jc.getActionMap();
InputMap im = jc.getInputMap(JComponent.WHEN_FOCUSED);
// This version doesn't work, for unknown reasons.
//JComponent contentPane = kMain.getContentPane();
//ActionMap am = contentPane.getActionMap();
//InputMap im = contentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
Action arrowUp = new ReflectiveAction("", null, this, "onArrowUp" );
Action arrowDown = new ReflectiveAction("", null, this, "onArrowDown" );
Action arrowLeft = new ReflectiveAction("", null, this, "onArrowLeft" );
Action arrowRight = new ReflectiveAction("", null, this, "onArrowRight");
// Register listeners for arrows with all combinations of Shift and Ctrl
am.put("arrow-up", arrowUp );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP , 0), "arrow-up" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP , KeyEvent.SHIFT_MASK), "arrow-up" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP , KeyEvent.CTRL_MASK), "arrow-up" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP , KeyEvent.SHIFT_MASK|KeyEvent.CTRL_MASK), "arrow-up" );
am.put("arrow-down", arrowDown );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN , 0), "arrow-down" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN , KeyEvent.SHIFT_MASK), "arrow-down" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN , KeyEvent.CTRL_MASK), "arrow-down" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN , KeyEvent.SHIFT_MASK|KeyEvent.CTRL_MASK), "arrow-down" );
am.put("arrow-left", arrowLeft );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0), "arrow-left" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , KeyEvent.SHIFT_MASK), "arrow-left" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , KeyEvent.CTRL_MASK), "arrow-left" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , KeyEvent.SHIFT_MASK|KeyEvent.CTRL_MASK), "arrow-left" );
am.put("arrow-right", arrowRight );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT , 0), "arrow-right" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT , KeyEvent.SHIFT_MASK), "arrow-right" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT , KeyEvent.CTRL_MASK), "arrow-right" );
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT , KeyEvent.SHIFT_MASK|KeyEvent.CTRL_MASK), "arrow-right" );
}
}
//}}}
//{{{ Mouse listeners
//##################################################################################################
// All of these just 'bounce' the event to the current active tool
public void mouseDragged(MouseEvent ev)
{
activeTool.mouseDragged(ev);
}
public void mouseMoved(MouseEvent ev)
{
activeTool.mouseMoved(ev);
}
public void mouseClicked(MouseEvent ev)
{
activeTool.mouseClicked(ev);
}
public void mouseEntered(MouseEvent ev)
{
activeTool.mouseEntered(ev);
}
public void mouseExited(MouseEvent ev)
{
activeTool.mouseExited(ev);
}
public void mousePressed(MouseEvent ev)
{
// required for the keyboard arrows, etc
// to pick up events!
kCanvas.requestFocus();
activeTool.mousePressed(ev);
}
public void mouseReleased(MouseEvent ev)
{
activeTool.mouseReleased(ev);
}
/**
* Not a real listener. Exists for other systems to "fake"
* mouse wheel events, e.g. through arrow keys.
* If we're in Java 1.4, real wheel events will be
* redirected here by ToolBoxMW.
*/
public void mouseWheelMoved(MouseEvent ev, int rotation)
{
activeTool.mouseWheelMoved(ev, rotation);
}
//}}}
//{{{ onArrowUp/Down/Right/Left
//##################################################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowUp(ActionEvent ev)
{
activeTool.onArrowUp(ev);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowDown(ActionEvent ev)
{
activeTool.onArrowDown(ev);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowRight(ActionEvent ev)
{
activeTool.onArrowRight(ev);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onArrowLeft(ActionEvent ev)
{
activeTool.onArrowLeft(ev);
}
//}}}
//{{{ signalTransform, overpaintCanvas
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
* This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
// Plugins:
sigTransform.signalTransform(engine, xform);
// Markers:
services.signalTransform(engine, xform);
// Active tool:
activeTool.signalTransform(engine, xform);
}
/**
* Called by KinCanvas after all kinemage painting is complete,
* this gives the tools a chance to write additional info
* (e.g., point IDs) to the graphics area.
* @param painter the Painter that can paint on the current canvas
*/
public void overpaintCanvas(Painter painter)
{
services.overpaintCanvas(painter);
activeTool.overpaintCanvas(painter);
}
//}}}
//{{{ empty_code_segment
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/JoglCanvas.java 0000644 0000000 0000000 00000026354 11531212674 017656 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.AffineTransform;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.r3.*;
import driftwood.util.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
//}}}
/**
* JoglCanvas
is a wrapper for a Painter that uses
* the OpenGL libraries for hardware-accelerated 2D rendering
* via the JOGL Java library.
*
*
Despite dire warnings about mixing heavyweight and lightweight components,
* it doesn't appear to be a problem unless a lightweight component were
* supposed to paint over top of this one...
*
*
Painting with a Graphics2D *is* possible via a mostly-transparent
* image with its own Graphics2D.
* However, Java prefers ARGB-int graphics and OpenGL requires RGBA-byte graphics.
* For some reason, it's MUCH faster to let Java draw on the ARGB graphics and
* then map the bytes into an array ourselves than it is to draw directly on a
* BufferedImage backed by a byte array.
* The two perform at roughly comparable speeds (30 - 35 ms) if nothing is drawn.
* However, the speeds are ~50 ms vs 1-2 SECONDS if even one text string is drawn.
*
This mode of doing the canvas overpaint has been replaced by one that uses
* the JoglPainter directly (which then uses the GLUT font functions for text).
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Sat Jun 5 15:47:31 EDT 2004
*/
public class JoglCanvas extends JPanel implements GLEventListener, TransformSignalSubscriber, MouseListener
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
KingMain kMain;
Engine engine;
ToolBox toolbox;
GLCanvas canvas;
Dimension glSize = new Dimension();
// Variables for doing text with a Graphics2D then overlaying it
//WritableRaster raster = null;
//BufferedImage overlayImg = null;
//byte[] overlayData = null;
//}}}
//{{{ Constructor(s)
//##############################################################################
public JoglCanvas(KingMain kMain, Engine engine, ToolBox toolbox)
{
super(new BorderLayout());
this.kMain = kMain;
this.engine = engine;
this.toolbox = toolbox;
// Java 1.4+ only! - adds support for Drag & Drop to the canvas
new FileDropHandler(kMain, this);
// Create and listen to an OpenGL canvas
GLCapabilities capabilities = new GLCapabilities();
capabilities.setDoubleBuffered(true); // usually enabled by default, but to be safe...
int fsaaNumSamples = kMain.getPrefs().getInt("joglNumSamples");
capabilities.setSampleBuffers(fsaaNumSamples > 1); // enables/disables full-scene antialiasing (FSAA)
capabilities.setNumSamples(fsaaNumSamples); // sets number of samples for FSAA (default is 2)
//canvas = GLDrawableFactory.getFactory().createGLCanvas(capabilities);
canvas = new GLCanvas(capabilities);
canvas.addGLEventListener(this); // calls display(), reshape(), etc.
canvas.addMouseListener(this); // cursor related; see this.mouseEntered().
toolbox.listenTo(canvas);
this.add(canvas, BorderLayout.CENTER);
}
//}}}
//{{{ init, display, reshape, displayChanged
//##############################################################################
public void init(GLAutoDrawable drawable)
{}
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
Kinemage kin = kMain.getKinemage();
if(kin == null)
{
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
}
else
{
JoglPainter painter = new JoglPainter(drawable);
long timestamp = System.currentTimeMillis();
KingView view = kin.getCurrentView();
Rectangle bounds = new Rectangle(this.glSize);
engine.syncToKin(kin);
engine.render(this, view, bounds, painter);
if(toolbox != null) toolbox.overpaintCanvas(painter);
timestamp = System.currentTimeMillis() - timestamp;
if(kMain.getCanvas().writeFPS)
SoftLog.err.println(timestamp+" ms ("+(timestamp > 0 ? Long.toString(1000/timestamp) : ">1000")
+" FPS) - "+engine.getNumberPainted()+" objects painted");
}
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
{
GL gl = drawable.getGL();
//GLU glu = drawable.getGLU();
GLU glu = new GLU();
this.glSize.setSize(width, height);
gl.glViewport(0, 0, width, height); // left, right, width, height
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluOrtho2D(0.0, width, -height, 0.0); // left, right, bottom, top
}
public void displayChanged(GLAutoDrawable drawable, boolean modeChnaged, boolean deviceChanged)
{}
//}}}
//{{{ getPreferred/MinimumSize, requestRepaint
//##############################################################################
public Dimension getPreferredSize()
{
return kMain.getCanvas().getPreferredSize();
}
public Dimension getMinimumSize()
{
return kMain.getCanvas().getMinimumSize();
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void requestRepaint(ActionEvent ev)
{
canvas.repaint();
}
//}}}
//{{{ signalTransform
//##################################################################################################
/**
* A call to this method indicates the subscriber
* should transform its coordinates from model-space
* to display-space and optionally add one or more
* KPoints to the supplied Engine using addPaintable().
*
*
This method will be called in response to TransformSignal.signalTransform().
*
* @param engine the Engine object describing the
* dimensions and properties of the space to be painted.
* @param xform the Transform to apply.
* The subscriber must not modify the original Transform it
* receives! Subscibers may, however, copy and modify the
* Transform(s) they pass to internal substructures.
*/
public void signalTransform(Engine engine, Transform xform)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signalTransform(engine, xform);
if(toolbox != null) toolbox.signalTransform(engine, xform);
}
//}}}
//{{{ SLOW - setupOverlay, getOverlayBytes
//##############################################################################
/*
Graphics2D setupOverlay()
{
if(overlayImg == null || overlayImg.getWidth() != glSize.width || overlayImg.getHeight() != glSize.height)
{
// Magic spells from the "Jumping into JOGL" article
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, glSize.width, glSize.height, 4, null);
ComponentColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {8,8,8,8},
true, false, ComponentColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE);
overlayImg = new BufferedImage(colorModel, raster, false, null);
}
Graphics2D g = overlayImg.createGraphics();
// Wipe out all data currently in image with invisible black.
// The for loop is MUCH faster -- maybe 10x or more.
//g.setColor(new Color(0,0,0,0));
//g.fillRect(0, 0, glSize.width, glSize.height);
byte[] overlayData = ((DataBufferByte)raster.getDataBuffer()).getData();
for(int i = 0; i < overlayData.length; i++) overlayData[i] = 0;
// Compensate for OpenGL Y-axis running the other way 'round
AffineTransform t = new AffineTransform();
t.translate(0, glSize.height);
t.scale(1.0, -1.0);
g.transform(t);
return g;
}
byte[] getOverlayBytes()
{
return ((DataBufferByte)raster.getDataBuffer()).getData();
}
*/
//}}}
//{{{ FAST - setupOverlay, getOverlayBytes
//##############################################################################
/*
Graphics2D setupOverlay()
{
if(overlayImg == null || overlayImg.getWidth() != glSize.width || overlayImg.getHeight() != glSize.height)
{
overlayImg = new BufferedImage(glSize.width, glSize.height, BufferedImage.TYPE_INT_ARGB);
int[] data = ((DataBufferInt)overlayImg.getRaster().getDataBuffer()).getData();
overlayData = new byte[4 * data.length];
}
Graphics2D g = overlayImg.createGraphics();
// Wipe out all data currently in image with invisible black.
// The for loop is MUCH faster -- maybe 10x or more.
//g.setColor(new Color(0,0,0,0));
//g.fillRect(0, 0, glSize.width, glSize.height);
int[] data = ((DataBufferInt)overlayImg.getRaster().getDataBuffer()).getData();
for(int i = 0; i < data.length; i++) data[i] = 0;
// Compensate for OpenGL Y-axis running the other way 'round
AffineTransform t = new AffineTransform();
t.translate(0, glSize.height);
t.scale(1.0, -1.0);
g.transform(t);
return g;
}
byte[] getOverlayBytes()
{
int i = 0, j = 0;
int[] data = ((DataBufferInt)overlayImg.getRaster().getDataBuffer()).getData();
while(i < data.length)
{
int d = data[i];
if(d == 0)
{
overlayData[j] = overlayData[j+1] = overlayData[j+2] = overlayData[j+3] = 0;
}
else // pack into RGBA order from ARGB ints
{
overlayData[j] = (byte)((d>>16) & 0xff);
overlayData[j+1] = (byte)((d>> 8) & 0xff);
overlayData[j+2] = (byte)((d ) & 0xff);
overlayData[j+3] = (byte)((d>>24) & 0xff);
}
i+=1;
j+=4;
}
return overlayData;
}
*/
//}}}
//{{{ Mouse listeners (for cursor)
//##################################################################################################
public void mouseEntered(MouseEvent ev)
{
// This is the only thing that removes the <-|-> cursor from the split pane.
// Forces update of cursor for top level native peer (i.e. window, not GL canvas):
this.setCursor( Cursor.getDefaultCursor() );
//canvas.setCursor( Cursor.getDefaultCursor() ); // not needed
}
public void mouseExited(MouseEvent ev) {}
public void mousePressed(MouseEvent ev) {}
public void mouseReleased(MouseEvent ev) {}
public void mouseClicked(MouseEvent ev) {}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/GridBagPanel.java 0000644 0000000 0000000 00000014517 11531212674 020104 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
//import java.io.*;
//import java.net.*;
//import java.text.*;
//import java.util.*;
import javax.swing.*;
//import gnu.regexp.*;
//}}}
/**
* GridBagPanel
is just a JPanel with a GridBagLayout and some convenience functions.
* To set default constraints, access the gbc
member variable.
*
*
Functions that set alignment properties, etc. take effect only until the next add() is called.
* They return a reference to this same GridBagPanel so function calls can be "chained", like
* java.lang.StringBuffer allows.
*
*
Copyright (C) 2002 by Ian W. Davis. All rights reserved.
*
Begun on Tue Jul 2 09:08:06 EDT 2002
*/
public class GridBagPanel extends JPanel // implements ...
{
//{{{ Static fields
//}}}
//{{{ Variable definitions
//##################################################################################################
GridBagLayout gbl;
/** These are the default constraints for all objects added to the panel */
public GridBagConstraints gbc;
/** These are the derived constraints for the next component to be added */
GridBagConstraints derived;
//}}}
//{{{ Constructors
//##################################################################################################
/**
* Creates a new panel and installs a GridBagLayout on it.
*/
public GridBagPanel()
{
super();
gbl = new GridBagLayout();
gbc = new GridBagConstraints();
derived = null;
setLayout(gbl);
}
//}}}
//{{{ add(...) functions
//##################################################################################################
public void add(Component comp, int x, int y)
{
if(derived == null) rederive();
if(x == -1) derived.gridx = GridBagConstraints.RELATIVE;
else derived.gridx = x;
if(y == -1) derived.gridy = GridBagConstraints.RELATIVE;
else derived.gridy = y;
gbl.setConstraints(comp, derived);
this.add(comp);
derived = null;
}
public void add(Component comp, int x, int y, int w, int h)
{
if(derived == null) rederive();
span(w, h).add(comp, x, y);
}
public void add(Component comp, int x, int y, int w, int h, int fill, int anchor)
{
if(derived == null) rederive();
derived.fill = fill;
derived.anchor = anchor;
span(w, h).add(comp, x, y);
}
public void add(Component comp, int x, int y, int w, int h, int fill, int anchor, double wx, double wy)
{
if(derived == null) rederive();
derived.fill = fill;
derived.anchor = anchor;
span(w, h).weight(wx, wy).add(comp, x, y);
}
//}}}
//{{{ rederive, span, weight, insets
//##################################################################################################
/** Resets derived properties to be the same as defaults. */
void rederive()
{ derived = (GridBagConstraints)gbc.clone(); }
/** Sets gridwidth and gridheight for the next component added */
public GridBagPanel span(int x, int y)
{
if(derived == null) rederive();
derived.gridwidth = x;
derived.gridheight = y;
return this;
}
/** Sets weightx and weighty for the next component added */
public GridBagPanel weight(double x, double y)
{
if(derived == null) rederive();
derived.weightx = x;
derived.weighty = y;
return this;
}
/** Sets the insets for the next component added */
public GridBagPanel insets(int top, int left, int bottom, int right)
{
if(derived == null) rederive();
derived.insets = new Insets(top, left, bottom, right);
return this;
}
//}}}
//{{{ fillNone, fillH, fillV, fillBoth
//##################################################################################################
public GridBagPanel fillNone()
{
if(derived == null) rederive();
derived.fill = GridBagConstraints.NONE;
return this;
}
public GridBagPanel fillH()
{
if(derived == null) rederive();
derived.fill = GridBagConstraints.HORIZONTAL;
return this;
}
public GridBagPanel fillV()
{
if(derived == null) rederive();
derived.fill = GridBagConstraints.VERTICAL;
return this;
}
public GridBagPanel fillBoth()
{
if(derived == null) rederive();
derived.fill = GridBagConstraints.BOTH;
return this;
}
//}}}
//{{{ anchor functions (center, north, northwest, etc.)
//##################################################################################################
public GridBagPanel center()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.CENTER;
return this;
}
public GridBagPanel north()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.NORTH;
return this;
}
public GridBagPanel northeast()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.NORTHEAST;
return this;
}
public GridBagPanel east()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.EAST;
return this;
}
public GridBagPanel southeast()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.SOUTHEAST;
return this;
}
public GridBagPanel south()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.SOUTH;
return this;
}
public GridBagPanel southwest()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.SOUTHWEST;
return this;
}
public GridBagPanel west()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.WEST;
return this;
}
public GridBagPanel northwest()
{
if(derived == null) rederive();
derived.anchor = GridBagConstraints.NORTHWEST;
return this;
}
//}}}
//{{{ empty
//##################################################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/AxisChooser.java 0000644 0000000 0000000 00000010723 11531212674 020047 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.gui.*;
//}}}
/**
* AxisChooser
is the GUI for mapping high-dimensional kinemages
* onto the X, Y, and Z axes.
*
*
Copyright (C) 2006 by Ian W. Davis. All rights reserved.
*
Begun on Tue Jun 13 16:10:45 EDT 2006
*/
public class AxisChooser //extends ... implements ...
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
KingMain kMain;
Kinemage kin;
int kinDimension;
Collection dimNames;
JList xAxisList, yAxisList, zAxisList;
//}}}
//{{{ Constructor(s)
//##############################################################################
public AxisChooser(KingMain kMain, Kinemage kin)
{
super();
this.kMain = kMain;
this.kin = kin;
this.kinDimension = getKinDimension(kin);
this.dimNames = new ArrayList(kin.dimensionNames);
for(int i = dimNames.size(); i < kinDimension; i++)
dimNames.add("Axis "+(i+1));
buildGUI();
}
//}}}
//{{{ buildGUI
//##############################################################################
private void buildGUI()
{
final int visibleRows = 10;
xAxisList = new FatJList(0, 10);
xAxisList.setVisibleRowCount(visibleRows);
xAxisList.setListData(dimNames.toArray());
xAxisList.setSelectedIndex(Math.min(0, dimNames.size()-1));
yAxisList = new FatJList(0, 10);
yAxisList.setVisibleRowCount(visibleRows);
yAxisList.setListData(dimNames.toArray());
yAxisList.setSelectedIndex(Math.min(1, dimNames.size()-1));
zAxisList = new FatJList(0, 10);
zAxisList.setVisibleRowCount(visibleRows);
zAxisList.setListData(dimNames.toArray());
zAxisList.setSelectedIndex(Math.min(2, dimNames.size()-1));
JButton btnOK = new JButton(new ReflectiveAction("Set axes", null, this, "onSetAxes"));
TablePane2 cp = new TablePane2();
cp.insets(10).memorize();
cp.add(new JLabel("X axis"));
cp.add(new JLabel("Y axis"));
cp.add(new JLabel("Z axis"));
cp.newRow();
cp.add(new JScrollPane(xAxisList));
cp.add(new JScrollPane(yAxisList));
cp.add(new JScrollPane(zAxisList));
cp.newRow();
cp.startSubtable(3,1).center().addCell(btnOK).endSubtable();
JDialog dialog = new JDialog(kMain.getTopWindow(), "Choose axes", false /* not modal */);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setContentPane(cp);
dialog.pack();
dialog.show(); // will return immediately, b/c dialog is non-modal
}
//}}}
//{{{ onSetAxes
//##############################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onSetAxes(ActionEvent ev)
{
int xIndex = Math.max(0, xAxisList.getSelectedIndex());
int yIndex = Math.max(1, yAxisList.getSelectedIndex());
int zIndex = Math.max(2, zAxisList.getSelectedIndex());
KingView.setAxes(kin, xIndex, yIndex, zIndex);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ getKinDimension
//##############################################################################
/**
* Figures out how many axes are present in this kinemage (i.e. its dimension).
*/
static public int getKinDimension(Kinemage kin)
{
int numAxes = 0;
for(Iterator gi = kin.iterator(); gi.hasNext(); )
{
KGroup group = (KGroup) gi.next();
for(Iterator si = group.iterator(); si.hasNext(); )
{
KSubgroup subgroup = (KSubgroup) si.next();
for(Iterator li = subgroup.iterator(); li.hasNext(); )
{
KList list = (KList) li.next();
numAxes = Math.max(numAxes, list.getDimension());
}
}
}
return numAxes;
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/tool/ 0000755 0000000 0000000 00000000000 11744310054 015724 5 ustar root root king-2.21.120420/king/1.x_src/king/tool/util/ 0000755 0000000 0000000 00000000000 11744310054 016701 5 ustar root root king-2.21.120420/king/1.x_src/king/tool/util/SelfUpdatePlugin.java 0000644 0000000 0000000 00000025655 11531212672 022775 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.tool.util;
import king.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.DecimalFormat;
import java.util.*;
import java.util.zip.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.gui.*;
import driftwood.util.*;
import king.ReflectiveRunnable;
import javax.swing.Timer; // not java.util.Timer
//}}}
/**
* SelfUpdatePlugin
allows the user to download the newest KiNG
* version and install it from within the KiNG program itself.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Sat May 22 11:53:49 EDT 2004
*/
public class SelfUpdatePlugin extends Plugin
{
//{{{ Constants
static final String UPDATE_ANYWAY =
"It appears that either you already have the latest version of KiNG,\n"+
"or that you are not connected to the network at this time.\n"+
"\n"+
"Do you still want to try updating KiNG?";
static final String ARE_YOU_SURE1 =
"This plugin will download the latest version of KiNG\n"+
"that is publicly available on the Kinemage website.\n"+
"It will then be installed over top of your current KiNG\n"+
"(";
static final String ARE_YOU_SURE2 =
"),\n"+
"completely replacing it.\n"+
"\n"+
"This action cannot be undone. Furthermore, there is always\n"+
"a small chance it may not perform correctly, potentially\n"+
"rendering KiNG unusable and forcing you to reinstall manually.\n"+
"Are you sure you want to continue?";
static final String UPDATE_FAILED =
"Due to circumstances beyond our control, the update failed.\n"+
"The most likely source of error is that you don't have permission\n"+
"to overwrite the KiNG installation, or that the network is down.\n"+
"More details about the error are available under Help | Error Log.\n"+
"\n"+
"Your copy of KiNG is probably OK, but it COULD have been damaged --\n"+
"if it acts strangely or refuses to start, you may have to reinstall.\n"+
"You can get a new copy of KiNG from http://kinemage.biochem.duke.edu.\n"+
"\n"+
"We are very sorry this happened. If you believe this is the result of\n"+
"a bug in KiNG or in this plugin, please report it to the author/maintainter,\n"+
"whose email address is listed in the user manual.";
static final String ABORT_OK =
"The update has been aborted.\n"+
"No changes have been made to KiNG.";
static final String UPDATE_OK =
"The update appears to have succeeded.\n"+
"Cross your fingers and restart KiNG\n"+
"for changes to take effect.";
//}}}
//{{{ Variable definitions
//##############################################################################
Timer progressTimer;
JProgressBar progressBar;
JDialog dialog;
volatile int totalSize = 1, downloadedSize = 0;
volatile boolean abortFlag = false;
volatile Throwable backgroundError = null;
//}}}
//{{{ Constructor(s)
//##############################################################################
public SelfUpdatePlugin(ToolBox tb)
{
super(tb);
progressTimer = new Timer(1000, new ReflectiveAction(null, null, this, "onProgressTimer"));
progressTimer.setCoalesce(true);
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
JButton btnCancel = new JButton(new ReflectiveAction("Cancel", null, this, "onDownloadCancel"));
TablePane2 cp = new TablePane2();
cp.insets(4).memorize();
cp.addCell(new JLabel("Downloading new version of KiNG from")).newRow();
cp.addCell(new JLabel("http://kinemage.biochem.duke.edu ...")).newRow();
cp.hfill(true).addCell(progressBar).newRow();
cp.center().addCell(btnCancel);
dialog = new JDialog(kMain.getTopWindow(), true);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setContentPane(cp);
}
//}}}
//{{{ toString, isAppletSafe, getToolsMenuItem, getHelpAnchor
//##############################################################################
public String toString()
{ return "Update KiNG"; }
public static boolean isAppletSafe()
{ return false; }
public JMenuItem getToolsMenuItem()
{
JMenuItem item = new JMenuItem(new ReflectiveAction(this.toString(), null, this, "onBeginUpdate"));
return item;
}
public String getHelpAnchor()
{ return "#update-plugin"; }
//}}}
//{{{ onProgressTimer, onDownloadCancel
//##############################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onProgressTimer(ActionEvent ev)
{
progressBar.setValue((100*downloadedSize)/totalSize);
}
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onDownloadCancel(ActionEvent ev)
{
abortFlag = true;
}
//}}}
//{{{ onBeginUpdate
//##############################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onBeginUpdate(ActionEvent ev)
{
KingPrefs prefs = kMain.getPrefs();
// Check with user before starting
if(! prefs.newerVersionAvailable()
&& JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(kMain.getTopWindow(), UPDATE_ANYWAY, "Update anyway?", JOptionPane.YES_NO_OPTION))
return;
String msg;
try { msg = ARE_YOU_SURE1 + prefs.jarFileDirectory.getCanonicalPath() + ARE_YOU_SURE2; }
catch(Exception ex) { msg = ARE_YOU_SURE1 + "unknown location" + ARE_YOU_SURE2; } // io, null ptr, security?
if(JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(kMain.getTopWindow(), msg, "Update KiNG?", JOptionPane.YES_NO_OPTION))
return;
this.downloadedSize = 0;
this.abortFlag = false;
this.backgroundError = null;
this.progressBar.setValue(0);
Thread backgroundJob = new Thread(new ReflectiveRunnable(this, "downloadFile"));
backgroundJob.start();
this.progressTimer.start();
this.dialog.pack();
this.dialog.setLocationRelativeTo(kMain.getTopWindow());
this.dialog.setVisible(true);
// execution halts here until the dialog is closed
}
//}}}
//{{{ downloadFile
//##############################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void downloadFile()
{
try
{
URL updateURL = new URL("http://kinemage.biochem.duke.edu/downloads/software/king/current");
URLConnection urlConn = updateURL.openConnection();
this.totalSize = urlConn.getContentLength();
this.downloadedSize = 0;
InputStream is = urlConn.getInputStream();
File tmpFile = File.createTempFile("kingupdate", null);
tmpFile.deleteOnExit();
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile));
//streamcopy(is, os);
byte[] buffer = new byte[2048];
int len;
while((len = is.read(buffer)) != -1 && !abortFlag)
{
os.write(buffer, 0, len);
this.downloadedSize += len;
}
os.close();
is.close();
if(!abortFlag)
{
ZipFile f = new ZipFile(tmpFile);
installZipFile(f);
f.close();
abortFlag = false; // just in case there was a sync. problem
}
}
catch(Throwable t)
{
this.backgroundError = t;
}
SwingUtilities.invokeLater(new ReflectiveRunnable(this, "onFinishUpdate"));
}
//}}}
//{{{ installZipFile, streamcopy
//##############################################################################
/**
* Unpacks the ZIP file into the directory where king.jar is currently located,
* after stripping off the initial king-x.xx/ path
*/
private void installZipFile(ZipFile zipfile) throws IOException
{
File dest = kMain.getPrefs().jarFileDirectory;
if(!dest.exists() || !dest.isDirectory() || !dest.canWrite())
throw new IOException("Unable to unpack downloaded ZIP into "+dest+"; check permissions/ownership?");
Enumeration entries = zipfile.entries();
while(entries.hasMoreElements())
{
ZipEntry e = (ZipEntry) entries.nextElement();
// Clip off king-x.xx/ prefix
String name = e.getName();
int i = name.indexOf("/");
if(i != -1) name = name.substring(i);
if(name.equals("")) continue;
// Create directory or write file
File f = new File(dest, name).getCanonicalFile();
if(e.isDirectory())
{
f.mkdirs();
}
else
{
InputStream is = zipfile.getInputStream(e);
OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
streamcopy(is, os);
os.close();
is.close();
}
}
}
// Copies src to dst until we hit EOF
void streamcopy(InputStream src, OutputStream dst) throws IOException
{
byte[] buffer = new byte[2048];
int len;
while((len = src.read(buffer)) != -1) dst.write(buffer, 0, len);
}
//}}}
//{{{ onFinishUpdate
//##############################################################################
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onFinishUpdate()
{
this.progressTimer.stop();
this.dialog.setVisible(false);
if(backgroundError != null)
{
backgroundError.printStackTrace(SoftLog.err);
JOptionPane.showMessageDialog(kMain.getTopWindow(), UPDATE_FAILED, "Update failed", JOptionPane.ERROR_MESSAGE);
}
else if(abortFlag)
{
// Don't really need to do anything.
JOptionPane.showMessageDialog(kMain.getTopWindow(), ABORT_OK, "Update aborted", JOptionPane.INFORMATION_MESSAGE);
}
else
{
JOptionPane.showMessageDialog(kMain.getTopWindow(), UPDATE_OK, "Update succeeded", JOptionPane.INFORMATION_MESSAGE);
}
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/tool/draw/ 0000755 0000000 0000000 00000000000 11744310054 016661 5 ustar root root king-2.21.120420/king/1.x_src/king/tool/draw/DrawingTool.java 0000644 0000000 0000000 00000132063 11531212672 021763 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.tool.draw;
import king.*;
import king.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import driftwood.gui.*;
import driftwood.r3.*;
//}}}
/**
* DrawingTool
provides many of the Mage "Draw New" functions.
*
*
Copyright (C) 2004 by Ian W. Davis. All rights reserved.
*
Begun on Thu Feb 26 16:25:47 EST 2004
*/
public class DrawingTool extends BasicTool
{
//{{{ Constants
static final int AUGER_RADIUS = 40;
//}}}
//{{{ Interface: UndoStep
//##############################################################################
interface UndoStep
{
/** Triggers the undo action */
public void undo();
}
//}}}
//{{{ Class: ListChildrenUndo
//##############################################################################
/*
* Provides a simple undo mechanism for all the drawing tools.
* Every time a list is changed, its children
field
* is cloned and saved here. The editing action can then be undone
* simply by copying this over top of the current children
.
*/
static class ListChildrenUndo implements UndoStep
{
KList list;
ArrayList children;
KPoint modPoint = null;
KPoint modPrev = null;
/* Saves the state of list l */
public ListChildrenUndo(KList l)
{
super();
this.list = l;
this.children = new ArrayList(l.children);
}
/** Saves the state of a point who's value of "prev" was set to null */
public void savePoint(KPoint p)
{
this.modPoint = p;
this.modPrev = p.getPrev();
}
/** Triggers the undo action */
public void undo()
{
list.children = this.children;
if(modPoint != null) modPoint.setPrev(modPrev);
}
}
//}}}
//{{{ Class: PointCoordsUndo
//##############################################################################
/** Allows us to undo moving points, eg when we drag them around. */
static class PointCoordsUndo implements UndoStep
{
KPoint[] points;
Triple[] coords;
public PointCoordsUndo(KPoint[] pts)
{
super();
this.points = (KPoint[]) pts.clone();
this.coords = new Triple[ points.length ];
for(int i = 0; i < points.length; i++)
coords[i] = new Triple(points[i]);
}
public void undo()
{
for(int i = 0; i < points.length; i++)
points[i].setXYZ(coords[i].getX(), coords[i].getY(), coords[i].getZ());
}
}
//}}}
//{{{ Variable definitions
//##############################################################################
TablePane2 ui;
JRadioButton rbDoNothing, rbRevealList, rbEditGroup, rbEditSubgroup, rbEditList,
rbEditPoint, rbPaintPoints, rbMovePoint;
JRadioButton rbLineSegment, rbDottedLine, rbArcSegment,
rbBalls, rbLabels, rbDots, rbTriangle;
JRadioButton rbPunch, rbPrune, rbAuger, rbSphereCrop;
Builder builder = new Builder();
KPoint lineseg1 = null, lineseg2 = null;
KPoint triang1 = null, triang2 = null, triang3 = null;
KPoint arcseg1 = null, arcseg2 = null, arcseg3 = null;
GroupEditor grEditor;
PointEditor ptEditor;
KPoint draggedPoint = null;
KPoint[] allPoints = null;
JComboBox cmPointPaint;
JTextField tfShortenLine;
JCheckBox cbLabelIsID;
JTextField tfNumDots;
JTextField tfArcDegrees, tfArcShorten;
JCheckBox cbArcArrowhead;
JTextField tfTriangleSize;
JTextField tfCropRadius;
/** Use add/removeLast() to enque UndoSteps wrapped in SoftReferences */
LinkedList undoStack;
/** Used by getDrawingList() to create new lists when subgroup is updated */
int subgroupCounter = 0;
/** Used by Auger for doing its marker drawing */
int lastAugerX, lastAugerY;
//}}}
//{{{ Constructor(s)
//##############################################################################
public DrawingTool(ToolBox tb)
{
super(tb);
grEditor = new GroupEditor(kMain, kMain.getTopWindow());
ptEditor = new PointEditor(kMain);
undoStack = new LinkedList();
buildGUI();
}
//}}}
//{{{ buildGUI
//##############################################################################
private void buildGUI()
{
ButtonGroup buttonGroup = new ButtonGroup();
// Build all the radio buttons for different drawing modes
rbDoNothing = new JRadioButton("Do nothing (navigate)");
buttonGroup.add(rbDoNothing);
rbRevealList = new JRadioButton("Reveal in hierarchy");
buttonGroup.add(rbRevealList);
rbEditGroup = new JRadioButton("Edit group props");
buttonGroup.add(rbEditGroup);
rbEditSubgroup = new JRadioButton("Edit subgroup props");
buttonGroup.add(rbEditSubgroup);
rbEditList = new JRadioButton("Edit list props");
buttonGroup.add(rbEditList);
rbEditPoint = new JRadioButton("Edit point props");
buttonGroup.add(rbEditPoint);
rbPaintPoints = new JRadioButton("Paint points");
buttonGroup.add(rbPaintPoints);
rbMovePoint = new JRadioButton("Move points");
buttonGroup.add(rbMovePoint);
rbLineSegment = new JRadioButton("Draw line segments");
buttonGroup.add(rbLineSegment);
rbDottedLine = new JRadioButton("Draw dotted lines");
buttonGroup.add(rbDottedLine);
rbArcSegment = new JRadioButton("Draw curved arc");
buttonGroup.add(rbArcSegment);
rbBalls = new JRadioButton("Draw balls");
buttonGroup.add(rbBalls);
rbLabels = new JRadioButton("Draw labels");
buttonGroup.add(rbLabels);
rbDots = new JRadioButton("Draw dots");
buttonGroup.add(rbDots);
rbTriangle = new JRadioButton("Draw triangles");
buttonGroup.add(rbTriangle);
rbPunch = new JRadioButton("Punch one point");
buttonGroup.add(rbPunch);
rbPrune = new JRadioButton("Prune a polyline");
buttonGroup.add(rbPrune);
rbAuger = new JRadioButton("Auger a region");
buttonGroup.add(rbAuger);
rbSphereCrop = new JRadioButton("Spherical crop");
buttonGroup.add(rbSphereCrop);
// Create the extra control panels
cmPointPaint = new JComboBox(KPalette.getStandardMap().values().toArray());
cmPointPaint.setSelectedItem(KPalette.green);
TablePane tpPaintPts = new TablePane();
tpPaintPts.addCell(new JLabel("Use color:"));
tpPaintPts.addCell(cmPointPaint);
FoldingBox fbPaintPts = new FoldingBox(rbPaintPoints, tpPaintPts);
fbPaintPts.setAutoPack(true);
fbPaintPts.setIndent(10);
tfShortenLine = new JTextField("0.0", 6);
TablePane tpLineSeg = new TablePane();
tpLineSeg.addCell(new JLabel("Shorten lines by:"));
tpLineSeg.addCell(tfShortenLine);
FoldingBox fbLineSeg = new FoldingBox(rbLineSegment, tpLineSeg);
fbLineSeg.setAutoPack(true);
fbLineSeg.setIndent(10);
tfNumDots = new JTextField("10", 6);
TablePane tpDottedLine = new TablePane();
tpDottedLine.addCell(new JLabel("Number of dots:"));
tpDottedLine.addCell(tfNumDots);
FoldingBox fbDottedLine = new FoldingBox(rbDottedLine, tpDottedLine);
fbDottedLine.setAutoPack(true);
fbDottedLine.setIndent(10);
tfArcDegrees = new JTextField("120", 6);
tfArcShorten = new JTextField("0", 6);
cbArcArrowhead = new JCheckBox("Arrowhead", false);
TablePane tpArcSegment = new TablePane();
tpArcSegment.addCell(new JLabel("Curvature (degrees):"));
tpArcSegment.addCell(tfArcDegrees);
tpArcSegment.newRow();
tpArcSegment.addCell(new JLabel("Shorten by (degrees):"));
tpArcSegment.addCell(tfArcShorten);
tpArcSegment.newRow();
tpArcSegment.addCell(cbArcArrowhead);
FoldingBox fbArcSegment = new FoldingBox(rbArcSegment, tpArcSegment);
fbArcSegment.setAutoPack(true);
fbArcSegment.setIndent(10);
cbLabelIsID = new JCheckBox("Use ID of picked point for label", false);
TablePane tpLabels = new TablePane();
tpLabels.addCell(cbLabelIsID);
FoldingBox fbLabels = new FoldingBox(rbLabels, tpLabels);
fbLabels.setAutoPack(true);
fbLabels.setIndent(10);
tfTriangleSize = new JTextField("1.0", 6);
TablePane tpTriangle = new TablePane();
tpTriangle.addCell(new JLabel("Fractional size:"));
tpTriangle.addCell(tfTriangleSize);
FoldingBox fbTriangle = new FoldingBox(rbTriangle, tpTriangle);
fbTriangle.setAutoPack(true);
fbTriangle.setIndent(10);
tfCropRadius = new JTextField("10", 6);
TablePane tpSphereCrop = new TablePane();
tpSphereCrop.addCell(new JLabel("Crop radius:"));
tpSphereCrop.addCell(tfCropRadius);
FoldingBox fbSphereCrop = new FoldingBox(rbSphereCrop, tpSphereCrop);
fbSphereCrop.setAutoPack(true);
fbSphereCrop.setIndent(10);
// Choose default drawing tool
rbEditList.setSelected(true);
// Create the UNDO button, etc
JButton btnUndo = new JButton(new ReflectiveAction("Undo drawing", null, this, "onUndo"));
JButton btnNewSubgroup = new JButton(new ReflectiveAction("New subgroup", null, this, "onNewSubgroup"));
// Put the UI together
ui = new TablePane2();
ui.hfill(true).vfill(true).insets(0,1,0,1).memorize();
ui.addCell(rbDoNothing).newRow();
ui.addCell(rbRevealList).newRow();
ui.addCell(rbEditGroup).newRow();
ui.addCell(rbEditSubgroup).newRow();
ui.addCell(rbEditList).newRow();
ui.addCell(rbEditPoint).newRow();
ui.addCell(rbPaintPoints).newRow();
ui.addCell(fbPaintPts).newRow();
ui.addCell(rbMovePoint).newRow();
ui.addCell(ui.strut(0,6)).newRow();
ui.addCell(rbLineSegment).newRow();
ui.addCell(fbLineSeg).newRow();
ui.addCell(rbDottedLine).newRow();
ui.addCell(fbDottedLine).newRow();
ui.addCell(rbArcSegment).newRow();
ui.addCell(fbArcSegment).newRow();
ui.addCell(rbBalls).newRow();
ui.addCell(rbLabels).newRow();
ui.addCell(fbLabels).newRow();
ui.addCell(rbDots).newRow();
ui.addCell(rbTriangle).newRow();
ui.addCell(fbTriangle).newRow();
ui.addCell(ui.strut(0,6)).newRow();
ui.addCell(rbPunch).newRow();
ui.addCell(rbPrune).newRow();
ui.addCell(rbAuger).newRow();
ui.addCell(rbSphereCrop).newRow();
ui.addCell(fbSphereCrop).newRow();
ui.addCell(btnNewSubgroup).newRow();
ui.addCell(btnUndo).newRow();
}
//}}}
//{{{ xx_click() functions
//##################################################################################################
/** Override this function for (left-button) clicks */
public void click(int x, int y, KPoint p, MouseEvent ev)
{
super.click(x, y, p, ev);
if(rbDoNothing.isSelected()) return; // don't mark kin as modified
else if(rbRevealList.isSelected()) doRevealList(x, y, p, ev);
else if(rbEditGroup.isSelected()) doEditGroup(x, y, p, ev);
else if(rbEditSubgroup.isSelected()) doEditSubgroup(x, y, p, ev);
else if(rbEditList.isSelected()) doEditList(x, y, p, ev);
else if(rbEditPoint.isSelected()) doEditPoint(x, y, p, ev);
else if(rbPaintPoints.isSelected()) doPaintPoints(x, y, p, ev);
else if(rbMovePoint.isSelected()) return; // don't mark kin as modified
else if(rbLineSegment.isSelected()) doLineSegment(x, y, p, ev);
else if(rbDottedLine.isSelected()) doDottedLine(x, y, p, ev);
else if(rbArcSegment.isSelected()) doArcSegment(x, y, p, ev);
else if(rbBalls.isSelected()) doBalls(x, y, p, ev);
else if(rbLabels.isSelected()) doLabels(x, y, p, ev);
else if(rbDots.isSelected()) doDots(x, y, p, ev);
else if(rbTriangle.isSelected()) doTriangle(x, y, p, ev);
else if(rbPunch.isSelected()) doPunch(x, y, p, ev);
else if(rbPrune.isSelected()) doPrune(x, y, p, ev);
else if(rbAuger.isSelected()) doAuger(x, y, p, ev);
else if(rbSphereCrop.isSelected()) doSphereCrop(x, y, p, ev);
Kinemage k = kMain.getKinemage();
if(k != null) k.setModified(true);
}
/** Override this function for middle-button/control clicks */
public void c_click(int x, int y, KPoint p, MouseEvent ev)
{ super.click(x, y, p, ev); }
//}}}
//{{{ onUndo
//##############################################################################
// target of reflection
public void onUndo(ActionEvent ev)
{
if(undoStack.size() < 1) return;
SoftReference ref = (SoftReference) undoStack.removeLast();
UndoStep step = (UndoStep) ref.get();
if(step == null) undoStack.clear(); // we should discard any other undos too
else step.undo();
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
// target of reflection
public void onNewSubgroup(ActionEvent ev)
{
// Forces creation of a new subgroup
// and triggers message to kinemage
this.getDrawingSubgroup(true);
}
//}}}
//{{{ getDrawingGroup, getDrawingSubgroup
//##############################################################################
/** Returns null if no kinemage is loaded */
protected KGroup getDrawingGroup()
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return null;
KGroup group = (KGroup)kin.metadata.get(this.getClass().getName()+".drawNewGroup");
if(group == null || group.getKinemage() == null) // signals that it's not bound to a kinemage -- has been deleted
{
group = new KGroup(kin, "Drawn objs");
//group.setDominant(true);
kin.add(group);
kin.metadata.put(this.getClass().getName()+".drawNewGroup", group);
kin.signal.signalKinemage(kin, KinemageSignal.STRUCTURE); // the new alternative to notifyChange()
}
return group;
}
/** Returns null if no kinemage is loaded */
protected KSubgroup getDrawingSubgroup(boolean forceCreate)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return null;
KGroup group = this.getDrawingGroup();
KSubgroup subgroup = (KSubgroup)kin.metadata.get(this.getClass().getName()+".drawNewSubgroup");
if(subgroup == null || forceCreate || subgroup.getKinemage() == null) // signals that it's not bound to a kinemage -- has been deleted
{
subgroupCounter++;
subgroup = new KSubgroup(group, "Drawn objs "+subgroupCounter);
subgroup.setDominant(true);
group.add(subgroup);
kin.metadata.put(this.getClass().getName()+".drawNewSubgroup", subgroup);
kin.signal.signalKinemage(kin, KinemageSignal.STRUCTURE); // the new alternative to notifyChange()
}
return subgroup;
}
//}}}
//{{{ getDrawingList
//##############################################################################
/**
* @param listType is one of the KList constants
* @param id is an identifier so one can have e.g. multiple vector lists
* @return null if no kinemage is loaded
*/
protected KList getDrawingList(String listType, String id)
{
Kinemage kin = kMain.getKinemage();
if(kin == null) return null;
KSubgroup subgroup = this.getDrawingSubgroup(false);
String listName = this.getClass().getName()+".drawNewList."+listType+"."+id+"."+subgroupCounter;
KList list = (KList)kin.metadata.get(listName);
if(list == null || list.getKinemage() == null) // signals that it's not bound to a kinemage -- has been deleted
{
list = new KList(subgroup, "Drawn "+listType+"s");
list.setType(listType);
KPaint[] colors = {KPalette.magenta, KPalette.green, KPalette.gold};
list.setColor(colors[subgroupCounter % colors.length]);
subgroup.add(list);
kin.metadata.put(listName, list);
kin.signal.signalKinemage(kin, KinemageSignal.STRUCTURE); // the new alternative to notifyChange()
}
return list;
}
//}}}
//{{{ doRevealList, doEditGroup/Subgroup/List/Point
//##############################################################################
public void doRevealList(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = (KList)p.getOwner();
if(list == null) return;
kMain.getKinTree().reveal(list);
kMain.getKinTree().show();
}
public void doEditGroup(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = (KList)p.getOwner();
if(list == null) return;
KSubgroup subgroup = (KSubgroup)list.getOwner();
if(subgroup == null) return;
KGroup group = (KGroup)subgroup.getOwner();
if(group == null) return;
if(grEditor.editGroup(group))
kMain.notifyChange(KingMain.EM_EDIT_GROSS);
}
public void doEditSubgroup(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = (KList)p.getOwner();
if(list == null) return;
KSubgroup subgroup = (KSubgroup)list.getOwner();
if(subgroup == null) return;
if(grEditor.editSubgroup(subgroup))
kMain.notifyChange(KingMain.EM_EDIT_GROSS);
}
public void doEditList(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = (KList)p.getOwner();
if(list == null) return;
if(grEditor.editList(list))
kMain.notifyChange(KingMain.EM_EDIT_GROSS);
}
public void doEditPoint(int x, int y, KPoint p, MouseEvent ev)
{
if(p != null) ptEditor.editPoint(p);
}
//}}}
//{{{ doPaintPoints
//##############################################################################
protected void doPaintPoints(int x, int y, KPoint p, MouseEvent ev)
{
Engine engine = kCanvas.getEngine();
Collection points = engine.pickAll2D(x, y, services.doSuperpick.isSelected(), AUGER_RADIUS);
// Painting can't be undone because so many
// points following those removed might be modified.
// Remove all the points
KPaint paintColor = (KPaint) cmPointPaint.getSelectedItem();
for(Iterator iter = points.iterator(); iter.hasNext(); )
{
p = (KPoint) iter.next();
p.setColor(paintColor);
}
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ doLineSegment
//##############################################################################
protected void doLineSegment(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
if(lineseg1 == null)
{
lineseg1 = p;
}
else// if(lineseg2 == null)
{
lineseg2 = p;
KList list = this.getDrawingList(KList.VECTOR, "lineSegment");
if(list == null) return;
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
// Calculate line shortening
double shorten = 0.0;
try { shorten = Double.parseDouble(tfShortenLine.getText()); }
catch(NumberFormatException ex) {}
double xlen = lineseg1.getOrigX() - lineseg2.getOrigX();
double ylen = lineseg1.getOrigY() - lineseg2.getOrigY();
double zlen = lineseg1.getOrigZ() - lineseg2.getOrigZ();
double len = Math.sqrt(xlen*xlen + ylen*ylen + zlen*zlen);
double a = 1.0 - shorten/len; // the multiplier used below
VectorPoint v1 = new VectorPoint(list, "drawn", null);
v1.setOrigX(a*lineseg1.getOrigX() + (1-a)*lineseg2.getOrigX());
v1.setOrigY(a*lineseg1.getOrigY() + (1-a)*lineseg2.getOrigY());
v1.setOrigZ(a*lineseg1.getOrigZ() + (1-a)*lineseg2.getOrigZ());
list.add(v1);
VectorPoint v2 = new VectorPoint(list, "drawn", v1);
v2.setOrigX(a*lineseg2.getOrigX() + (1-a)*lineseg1.getOrigX());
v2.setOrigY(a*lineseg2.getOrigY() + (1-a)*lineseg1.getOrigY());
v2.setOrigZ(a*lineseg2.getOrigZ() + (1-a)*lineseg1.getOrigZ());
list.add(v2);
lineseg1 = lineseg2 = null;
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
}
//}}}
//{{{ doBalls, doLabels
//##############################################################################
protected void doBalls(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = this.getDrawingList(KList.BALL, "balls");
if(list == null) return;
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
BallPoint b = new BallPoint(list, "drawn");
b.setOrigX(p.getOrigX());
b.setOrigY(p.getOrigY());
b.setOrigZ(p.getOrigZ());
list.add(b);
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
protected void doLabels(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = this.getDrawingList(KList.LABEL, "labels");
if(list == null) return;
Object labelText = p.getName();
if(!cbLabelIsID.isSelected())
{
labelText = JOptionPane.showInputDialog(kMain.getTopWindow(),
"Enter label text", "Enter label text",
JOptionPane.QUESTION_MESSAGE,
null, null, labelText);
if(labelText == null) return;
}
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
LabelPoint lbl = new LabelPoint(list, labelText.toString());
lbl.setOrigX(p.getOrigX());
lbl.setOrigY(p.getOrigY());
lbl.setOrigZ(p.getOrigZ());
list.add(lbl);
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ doDots
//##############################################################################
protected void doDots(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = this.getDrawingList(KList.DOT, "dots");
if(list == null) return;
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
DotPoint dt = new DotPoint(list, "drawn");
dt.setOrigX(p.getOrigX());
dt.setOrigY(p.getOrigY());
dt.setOrigZ(p.getOrigZ());
list.add(dt);
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ doDottedLine
//##############################################################################
protected void doDottedLine(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
if(lineseg1 == null)
{
lineseg1 = p;
}
else// if(lineseg2 == null)
{
lineseg2 = p;
KList list = this.getDrawingList(KList.DOT, "dottedLine");
if(list == null) return;
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
// Endpoints and working registers
Triple p1 = new Triple(lineseg1.getOrigX(), lineseg1.getOrigY(), lineseg1.getOrigZ());
Triple p2 = new Triple(lineseg2.getOrigX(), lineseg2.getOrigY(), lineseg2.getOrigZ());
Triple x1 = new Triple(), x2 = new Triple();
// Number of dots
int nDots = 10;
try { nDots = Math.max(1, Integer.parseInt(tfNumDots.getText())); }
catch(NumberFormatException ex) {}
// Draw dots
for(double i = 1; i <= nDots; i++)
{
x1.likeProd(1.0-(i/(nDots+1.0)), p1);
x2.likeProd(i/(nDots+1.0), p2);
x1.add(x2);
DotPoint dt = new DotPoint(list, "drawn");
dt.setOrigX(x1.getX());
dt.setOrigY(x1.getY());
dt.setOrigZ(x1.getZ());
list.add(dt);
}
lineseg1 = lineseg2 = null;
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
}
//}}}
//{{{ doArcSegment
//##############################################################################
protected void doArcSegment(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
if(arcseg1 == null) arcseg1 = p; // reference position
else if(arcseg2 == null) arcseg2 = p; // arc tail
else// if(arcseg3 == null)
{
arcseg3 = p; // arc head
KList list = this.getDrawingList(KList.VECTOR, "arcSegment");
if(list == null) return;
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
// R
//
// P---M-->Q
// . . .
// . . .
// C
Triple R = new Triple(arcseg1.getOrigX(), arcseg1.getOrigY(), arcseg1.getOrigZ());
Triple P = new Triple(arcseg2.getOrigX(), arcseg2.getOrigY(), arcseg2.getOrigZ());
Triple Q = new Triple(arcseg3.getOrigX(), arcseg3.getOrigY(), arcseg3.getOrigZ());
Triple M = new Triple().likeMidpoint(P, Q);
double arcDegrees = 90;
try { arcDegrees = Double.parseDouble(tfArcDegrees.getText()); }
catch(NumberFormatException ex) {}
if(arcDegrees < 1) arcDegrees = 1;
if(arcDegrees > 360) arcDegrees = 360;
double phi = (arcDegrees < 180 ? arcDegrees : 360 - arcDegrees);
double distPQ = P.distance(Q);
double distMQ = distPQ / 2;
double distMC = distMQ / Math.tan(Math.toRadians(phi/2));
Triple C = builder.construct4(R, Q, M, distMC, 90, (arcDegrees < 180 ? 180 : 0));
Triple Cx = new Triple().likeNormal(P, R, Q).add(C);
// Not good if angle=180 and Q, C, P are colinear!
//if(arcDegrees < 180) Cx.likeNormal(Q, C, P).add(C);
//else Cx.likeNormal(P, C, Q).add(C);
double shortenDegrees = 0;
try { shortenDegrees = Double.parseDouble(tfArcShorten.getText()); }
catch(NumberFormatException ex) {}
Triple rotPoint = new Triple();
Transform xform = new Transform();
VectorPoint v1 = null, prev = null;
for(double rotDegrees = shortenDegrees/2; rotDegrees <= (arcDegrees-shortenDegrees/2); rotDegrees+=1.0)
{
xform.likeRotation(C, Cx, rotDegrees);
xform.transform(P, rotPoint);
prev = v1;
v1 = new VectorPoint(list, "drawn", prev);
v1.setOrigX(rotPoint.getX());
v1.setOrigY(rotPoint.getY());
v1.setOrigZ(rotPoint.getZ());
list.add(v1);
}
// Add arrowheads here
if(cbArcArrowhead.isSelected())
{
Triple arrowBase = new Triple(prev.getOrigX(), prev.getOrigY(), prev.getOrigZ());
Triple arrowTip = new Triple(v1.getOrigX(), v1.getOrigY(), v1.getOrigZ());
makeArrowhead(R, arrowBase, arrowTip, 0.12*distPQ, 30, 4, list);
}
arcseg1 = arcseg2 = arcseg3 = null;
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
}
//}}}
//{{{ makeArrowhead
//##############################################################################
/**
* Creates an arrowhead.
* @param tine the first tine around the base-tip axis will point toward this point
* @param base the base of the arrow body
* @param tip the tip of the arrow
* @param tineLength the length of each tine
* @param tineAngle the angle of the tines to the arrow body
* @param tineCount how many tines will be created
* @param list the list in which to create the tines
*/
void makeArrowhead(Tuple3 tine, Tuple3 base, Tuple3 tip,
double tineLength, double tineAngle, int tineCount, KList list)
{
for(int i = 0; i < tineCount; i++)
{
Triple tineTip = builder.construct4(tine, base, tip, tineLength, tineAngle, (360.0*i)/tineCount);
VectorPoint v1 = new VectorPoint(list, "drawn", null);
v1.setOrigXYZ(tip);
list.add(v1);
VectorPoint v2 = new VectorPoint(list, "drawn", v1);
v2.setOrigXYZ(tineTip);
list.add(v2);
}
}
//}}}
//{{{ doTriangle
//##############################################################################
protected void doTriangle(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
if(triang1 == null)
triang1 = p;
else if(triang2 == null)
triang2 = p;
else// if(triang3 == null)
{
triang3 = p;
KList list = this.getDrawingList(KList.TRIANGLE, "triangle");
if(list == null) return;
undoStack.addLast(new SoftReference(new ListChildrenUndo(list)));
// Corner points
Triple p1 = new Triple(triang1.getOrigX(), triang1.getOrigY(), triang1.getOrigZ());
Triple p2 = new Triple(triang2.getOrigX(), triang2.getOrigY(), triang2.getOrigZ());
Triple p3 = new Triple(triang3.getOrigX(), triang3.getOrigY(), triang3.getOrigZ());
// Center point
Triple ctr = new Triple().add(p1).add(p2).add(p3).mult(1.0/3.0);
// Amount of shrinkage
double a = 1.0;
try { a = Math.abs(Double.parseDouble(tfTriangleSize.getText())); }
catch(NumberFormatException ex) {}
// Draw triangle
TrianglePoint t1 = new TrianglePoint(list, "drawn", null);
t1.setOrigX(a*p1.getX() + (1-a)*ctr.getX());
t1.setOrigY(a*p1.getY() + (1-a)*ctr.getY());
t1.setOrigZ(a*p1.getZ() + (1-a)*ctr.getZ());
list.add(t1);
TrianglePoint t2 = new TrianglePoint(list, "drawn", t1);
t2.setOrigX(a*p2.getX() + (1-a)*ctr.getX());
t2.setOrigY(a*p2.getY() + (1-a)*ctr.getY());
t2.setOrigZ(a*p2.getZ() + (1-a)*ctr.getZ());
list.add(t2);
TrianglePoint t3 = new TrianglePoint(list, "drawn", t2);
t3.setOrigX(a*p3.getX() + (1-a)*ctr.getX());
t3.setOrigY(a*p3.getY() + (1-a)*ctr.getY());
t3.setOrigZ(a*p3.getZ() + (1-a)*ctr.getZ());
list.add(t3);
triang1 = triang2 = triang3 = null;
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
}
//}}}
//{{{ doPunch, excisePoint
//##############################################################################
protected void doPunch(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = (KList) p.getOwner();
if(list == null) return;
ListChildrenUndo step = new ListChildrenUndo(list);
undoStack.addLast(new SoftReference(step));
excisePoint(p, step);
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
// Used by Punch and Auger -- not undoable in & of itself
// Step can be null, or it will be used to save the modified point.
private void excisePoint(KPoint p, ListChildrenUndo step)
{
if(p == null) return;
KList list = (KList) p.getOwner();
if(list == null) return;
for(ListIterator iter = list.children.listIterator(); iter.hasNext(); )
{
KPoint q = (KPoint) iter.next();
if(q == p)
{
iter.remove();
if(iter.hasNext())
{
q = (KPoint) iter.next();
if(step != null) step.savePoint(q);
q.setPrev(null);
}
break;
}//if we found the point
}//for all points in the list
}
//}}}
//{{{ doPrune
//##############################################################################
protected void doPrune(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
KList list = (KList) p.getOwner();
if(list == null) return;
ListChildrenUndo step = new ListChildrenUndo(list);
undoStack.addLast(new SoftReference(step));
for(ListIterator iter = list.children.listIterator(); iter.hasNext(); )
{
KPoint q = (KPoint) iter.next();
if(q == p)
{
iter.remove();
if(q.getPrev() != null)
{
while(iter.hasPrevious()) // remove preceding points
{
q = (KPoint) iter.previous();
iter.remove();
if(q.getPrev() == null) break;
}
}
while(iter.hasNext()) // remove following points
{
q = (KPoint) iter.next();
if(q.getPrev() == null) break;
iter.remove();
}
break;
}
}
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ doAuger
//##############################################################################
protected void doAuger(int x, int y, KPoint p, MouseEvent ev)
{
Engine engine = kCanvas.getEngine();
Collection points = engine.pickAll2D(x, y, services.doSuperpick.isSelected(), AUGER_RADIUS);
// Augering can't be undone because so many
// points following those removed might be modified.
// Remove all the points
for(Iterator iter = points.iterator(); iter.hasNext(); )
{
p = (KPoint) iter.next();
excisePoint(p, null);
}
Kinemage kin = kMain.getKinemage();
if(kin == null) return;
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ doSphereCrop
//##############################################################################
protected void doSphereCrop(int x, int y, KPoint p, MouseEvent ev)
{
if(p == null) return;
Kinemage kin = p.getKinemage();
if(kin == null) return;
double r = 10;
try { r = Double.parseDouble(tfCropRadius.getText()); }
catch(NumberFormatException ex) {}
double r2 = r*r;
// Cropping can't be undone because so many
// points following those removed might be modified.
// Find all the points THAT ARE CURRENTLY VISIBLE
// and outside the cropping sphere.
RecursivePointIterator rpi = new RecursivePointIterator(kin, false, true); // inc. unpickables
ArrayList toRemove = new ArrayList();
while(rpi.hasNext())
{
KPoint q = rpi.next();
double dx = p.getOrigX() - q.getOrigX();
double dy = p.getOrigY() - q.getOrigY();
double dz = p.getOrigZ() - q.getOrigZ();
if(dx*dx + dy*dy + dz*dz > r2 && q.isTotallyOn())
toRemove.add(q);
}
// Now remove them
for(Iterator iter = toRemove.iterator(); iter.hasNext(); )
excisePoint( (KPoint)iter.next(), null );
kin.signal.signalKinemage(kin, KinemageSignal.APPEARANCE);
}
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
//{{{ xx_drag() functions
//##################################################################################################
/** Override this function for (left-button) drags */
public void drag(int dx, int dy, MouseEvent ev)
{
KingView v = kMain.getView();
if(rbMovePoint.isSelected() && v != null && allPoints != null)
{
Dimension dim = kCanvas.getCanvasSize();
for(int k = 0; k < allPoints.length; k++)
{
float[] offset = v.translateRotated(dx, -dy, 0, Math.min(dim.width, dim.height));
// Check to make sure this isn't just a SpherePoint disk:
if(allPoints[k] instanceof ProxyPoint) continue;
allPoints[k].setOrigX(allPoints[k].getOrigX() + offset[0]);
allPoints[k].setOrigY(allPoints[k].getOrigY() + offset[1]);
allPoints[k].setOrigZ(allPoints[k].getOrigZ() + offset[2]);
}
Kinemage k = kMain.getKinemage();
if(k != null) k.setModified(true);
kCanvas.repaint();
}
else super.drag(dx, dy, ev);
}
/** Override this function for middle-button/control drags */
public void c_drag(int dx, int dy, MouseEvent ev)
{
KingView v = kMain.getView();
if(rbMovePoint.isSelected() && v != null && draggedPoint != null)
{
Dimension dim = kCanvas.getCanvasSize();
float[] offset = v.translateRotated(dx, -dy, 0, Math.min(dim.width, dim.height));
draggedPoint.setOrigX(draggedPoint.getOrigX() + offset[0]);
draggedPoint.setOrigY(draggedPoint.getOrigY() + offset[1]);
draggedPoint.setOrigZ(draggedPoint.getOrigZ() + offset[2]);
Kinemage k = kMain.getKinemage();
if(k != null) k.setModified(true);
kCanvas.repaint();
}
else super.c_drag(dx, dy, ev);
}
//}}}
//{{{ xx_wheel() functions
//##################################################################################################
/** Override this function for mouse wheel motion */
public void wheel(int rotation, MouseEvent ev)
{
KingView v = kMain.getView();
if(rbMovePoint.isSelected() && v != null && draggedPoint != null)
{
Dimension dim = kCanvas.getCanvasSize();
for(int k = 0; k < allPoints.length; k++)
{
float[] offset = v.translateRotated(0, 0, 6*rotation, Math.min(dim.width, dim.height));
allPoints[k].setOrigX(allPoints[k].getOrigX() + offset[0]);
allPoints[k].setOrigY(allPoints[k].getOrigY() + offset[1]);
allPoints[k].setOrigZ(allPoints[k].getOrigZ() + offset[2]);
}
Kinemage k = kMain.getKinemage();
if(k != null) k.setModified(true);
kCanvas.repaint();
}
else super.wheel(rotation, ev);
}
/** Override this function for mouse wheel motion with control down */
public void c_wheel(int rotation, MouseEvent ev)
{
KingView v = kMain.getView();
if(rbMovePoint.isSelected() && v != null && draggedPoint != null)
{
Dimension dim = kCanvas.getCanvasSize();
float[] offset = v.translateRotated(0, 0, 6*rotation, Math.min(dim.width, dim.height));
draggedPoint.setOrigX(draggedPoint.getOrigX() + offset[0]);
draggedPoint.setOrigY(draggedPoint.getOrigY() + offset[1]);
draggedPoint.setOrigZ(draggedPoint.getOrigZ() + offset[2]);
Kinemage k = kMain.getKinemage();
if(k != null) k.setModified(true);
kCanvas.repaint();
}
else super.c_wheel(rotation, ev);
}
//}}}
//{{{ mousePressed, mouseReleased
//##################################################################################################
public void mousePressed(MouseEvent ev)
{
super.mousePressed(ev);
if(kMain.getKinemage() != null)
draggedPoint = kCanvas.getEngine().pickPoint(ev.getX(), ev.getY(), services.doSuperpick.isSelected());
else draggedPoint = null;
// Otherwise, we just create a nonsensical warning message about stereo picking
if(draggedPoint == null)
allPoints = null;
else if(draggedPoint instanceof LabelPoint)
{
// Labels should never drag other points with them!
allPoints = new KPoint[] {draggedPoint};
}
else
{
// The 0.5 allows for a little roundoff error,
// both in the kinemage itself and our floating point numbers.
Collection all = kCanvas.getEngine().pickAll3D(
draggedPoint.getDrawX(), draggedPoint.getDrawY(), draggedPoint.getDrawZ(),
services.doSuperpick.isSelected(), 0.5);
allPoints = (KPoint[])all.toArray( new KPoint[all.size()] );
}
if(allPoints != null && rbMovePoint.isSelected())
undoStack.addLast(new SoftReference(new PointCoordsUndo(allPoints)));
}
public void mouseReleased(MouseEvent ev)
{
// Let's keep the point around so we can Z-translate too
//draggedPoint = null;
}
//}}}
//{{{ mouseMoved/Dragged/Exited, needAugerCircle, overpaintCanvas
//##################################################################################################
public void mouseMoved(MouseEvent ev)
{
super.mouseMoved(ev);
lastAugerX = ev.getX();
lastAugerY = ev.getY();
if(needAugerCircle()) // trigger a redraw
kCanvas.repaint();
}
public void mouseDragged(MouseEvent ev)
{
super.mouseDragged(ev);
lastAugerX = ev.getX();
lastAugerY = ev.getY();
// repaint will occur anyway
}
public void mouseExited(MouseEvent ev)
{
super.mouseExited(ev);
// Stop painting the marker at all when mouse leaves drawing area
lastAugerX = lastAugerY = -1;
if(needAugerCircle()) // trigger a redraw
kCanvas.repaint();
}
/** Do we need to see the circle that marks area of effect for Auger and similar tools? */
boolean needAugerCircle()
{ return rbAuger.isSelected() || rbPaintPoints.isSelected(); }
/**
* Called by KinCanvas after all kinemage painting is complete,
* this gives the tools a chance to write additional info
* (e.g., point IDs) to the graphics area.
*
We use it as an indication that the canvas has just been
* redrawn, so we may need to paint the area of effect for Auger.
* @param painter the Painter that can paint on the current canvas
*/
public void overpaintCanvas(Painter painter)
{
if(lastAugerX < 0 || lastAugerY < 0) return;
if(needAugerCircle())
{
double diam = AUGER_RADIUS * 2;
painter.drawOval(new Color(0xcc0000), lastAugerX, lastAugerY, 0, diam, diam);
}
}
//}}}
//{{{ getToolPanel, getHelpAnchor, toString
//##################################################################################################
/** Returns a component with controls and options for this tool */
protected Container getToolPanel()
{ return ui; }
/**
* Returns an anchor marking a place within king-manual.html
* that is the help for this tool. This is called by the default
* implementation of getHelpURL()
.
* If you override that function, you can safely ignore this one.
* @return for example, "#navigate-tool" (or null)
*/
public String getHelpAnchor()
{ return "#drawnew-tool"; }
public String toString() { return "Edit / draw / delete"; }
//}}}
}//class
king-2.21.120420/king/1.x_src/king/tool/export/ 0000755 0000000 0000000 00000000000 11744310054 017245 5 ustar root root king-2.21.120420/king/1.x_src/king/tool/export/PdfExport.java 0000644 0000000 0000000 00000016435 11531212672 022035 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.tool.export;
import king.*;
import king.core.Engine;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
import driftwood.util.SoftLog;
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
//}}}
/**
* PdfExport
uses the iText library to export the current graphics
* as a (vector) PDF file. The exact image is preserved, including
* the font on this platform and the rendering quality -- fully WYSIWYG.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Mon Sep 29 09:33:14 EDT 2003
*/
public class PdfExport extends Plugin implements PropertyChangeListener, Runnable
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
JFileChooser chooser;
SuffixFileFilter pdfFilter, pdftFilter;
//}}}
//{{{ Constructor(s)
//##############################################################################
public PdfExport(ToolBox tb)
{
super(tb);
buildChooser();
}
//}}}
//{{{ buildChooser
//##############################################################################
private void buildChooser()
{
pdfFilter = new SuffixFileFilter("Portable Document Format (PDF)");
pdfFilter.addSuffix(".pdf");
pdftFilter = new SuffixFileFilter("PDF with transparent background");
pdftFilter.addSuffix(".pdf");
String currdir = System.getProperty("user.dir");
chooser = new JFileChooser();
chooser.addChoosableFileFilter(pdfFilter);
chooser.addChoosableFileFilter(pdftFilter);
chooser.setFileFilter(pdfFilter);
if(currdir != null) chooser.setCurrentDirectory(new File(currdir));
chooser.addPropertyChangeListener(this);
}
//}}}
//{{{ exportPDF
//##############################################################################
static public void exportPDF(KinCanvas kCanvas, File outfile)
throws IOException, DocumentException
{ exportPDF(kCanvas, false, outfile); }
static public void exportPDF(KinCanvas kCanvas, boolean transparentBackground, File outfile)
throws IOException, DocumentException
{
Dimension dim = kCanvas.getCanvasSize();
Document doc = new Document(PageSize.LETTER, 72, 72, 72, 72); // 1" margins
PdfWriter pdf = PdfWriter.getInstance(doc, new FileOutputStream(outfile));
doc.addCreator("KiNG by Ian W. Davis");
// add header and footer now, before opening document
doc.open();
// Drawing code goes here. We use a template to simplify scaling/placement.
PdfContentByte content = pdf.getDirectContent();
PdfTemplate template = content.createTemplate((float)dim.getWidth(), (float)dim.getHeight());
Graphics2D g2 = template.createGraphics((float)dim.getWidth(), (float)dim.getHeight());
if(transparentBackground)
kCanvas.getEngine().setTransparentBackground();
kCanvas.paintCanvas(g2, dim, KinCanvas.QUALITY_BEST);
g2.dispose();
// Post-multiplied transformation matrix:
// [ x ] [ a b 0 ] [ x' ] [ x'/q ]
// [ y ] * [ c d 0 ] = [ y' ] = [ y'/q ]
// [ 1 ] [ e f 1 ] [ q ] [ 1 ]
// Top, left, botttom, and right already include margins.
// Coordinate system has bottom left corner as (0, 0)
double w = doc.right() - doc.left();
double h = doc.top() - doc.bottom();
float scale = (float)Math.min(w/dim.getWidth(), h/dim.getHeight());
// Place image at top left corner of page, respecting margins
content.addTemplate(template, scale, 0f, 0f, scale,
doc.left(),
(float)(doc.top() - scale*dim.getHeight()));
// Closing the document writes everything to file
doc.close();
}
//}}}
//{{{ askExport
//##############################################################################
public void askExport()
{
// Auto-generate a file name
propertyChange(null);
// Show the Save dialog
if(JFileChooser.APPROVE_OPTION == chooser.showSaveDialog(kMain.getTopWindow()))
{
File f = chooser.getSelectedFile();
if(!pdfFilter.accept(f) &&
JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(kMain.getTopWindow(),
"This file has the wrong extension. Append '.pdf' to the name?",
"Fix extension?", JOptionPane.YES_NO_OPTION))
{
f = new File(f+".pdf");
}
if(!f.exists() ||
JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(kMain.getTopWindow(),
"This file exists -- do you want to overwrite it?",
"Overwrite file?", JOptionPane.YES_NO_OPTION))
{
try
{
exportPDF(kMain.getCanvas(), pdftFilter.equals(chooser.getFileFilter()), f);
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(kMain.getTopWindow(),
"An error occurred while saving the file:\n"+ex.getMessage(),
"Sorry!", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace(SoftLog.err);
}
}
}
}
//}}}
//{{{ propertyChange, run
//##################################################################################################
public void propertyChange(PropertyChangeEvent ev)
{
if(ev == null
|| JFileChooser.FILE_FILTER_CHANGED_PROPERTY.equals(ev.getPropertyName())
|| JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(ev.getPropertyName()))
{
// Has to be done "asynchronously" or file name will be corrupted
SwingUtilities.invokeLater(this);
}
}
public void run()
{
String fmt = "pdf";
// Autogenerate an output name.
for(int i = 1; i < 1000; i++)
{
File f = new File(chooser.getCurrentDirectory(), "kingsnap"+i+"."+fmt);
if(!f.exists())
{
chooser.setSelectedFile(f);
break;
}
}
}
//}}}
//{{{ getToolsMenuItem, getHelpMenuItem, toString, onExport, isAppletSafe
//##################################################################################################
public JMenuItem getToolsMenuItem()
{
return new JMenuItem(new ReflectiveAction(this.toString()+"...", null, this, "onExport"));
}
public JMenuItem getHelpMenuItem()
{ return null; }
public String toString()
{ return "PDF document"; }
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onExport(ActionEvent ev)
{ this.askExport(); }
static public boolean isAppletSafe()
{ return false; }
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/tool/export/ImageExport.java 0000644 0000000 0000000 00000024656 11531212672 022352 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.tool.export;
import king.*;
import king.core.Engine;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
//import java.util.regex.*;
import javax.imageio.*; // J2SE 1.4+
import javax.imageio.stream.*; // J2SE 1.4+
import javax.swing.*;
import javax.swing.event.*;
import driftwood.gui.*;
import driftwood.util.SoftLog;
//}}}
/**
* ImageExport
allows the current graphics to be quickly
* exported as an image. The exact image is preserved, including
* the font on this platform and the rendering quality -- fully WYSIWYG.
* Only works in Java 1.4 or later.
*
*
Copyright (C) 2003 by Ian W. Davis. All rights reserved.
*
Begun on Mon Sep 29 09:33:14 EDT 2003
*/
public class ImageExport extends Plugin implements PropertyChangeListener, Runnable
{
//{{{ Constants
//}}}
//{{{ Variable definitions
//##############################################################################
JFileChooser chooser;
SuffixFileFilter jpgFilter, pngFilter, pngtFilter;
//}}}
//{{{ Constructor(s)
//##############################################################################
public ImageExport(ToolBox tb)
{
super(tb);
buildChooser();
}
//}}}
//{{{ buildChooser
//##############################################################################
private void buildChooser()
{
jpgFilter = new SuffixFileFilter("Joint Photographic Experts Group (JPEG)");
jpgFilter.addSuffix(".jpg");
jpgFilter.addSuffix(".jpe");
jpgFilter.addSuffix(".jpeg");
pngFilter = new SuffixFileFilter("Portable Network Graphics (PNG)");
pngFilter.addSuffix(".png");
pngtFilter = new SuffixFileFilter("PNG with transparent background");
pngtFilter.addSuffix(".png");
String currdir = System.getProperty("user.dir");
chooser = new JFileChooser();
chooser.addChoosableFileFilter(jpgFilter);
chooser.addChoosableFileFilter(pngFilter);
chooser.addChoosableFileFilter(pngtFilter);
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileFilter(jpgFilter);
if(currdir != null) chooser.setCurrentDirectory(new File(currdir));
chooser.addPropertyChangeListener(this);
}
//}}}
//{{{ exportImage
//##############################################################################
static public void exportImage(KinCanvas kCanvas, String format, File outfile)
throws IOException
{ exportImage(kCanvas, format, false, 1, outfile); }
static public void exportImage(KinCanvas kCanvas, String format, boolean transparentBackground, int resol, File outfile)
throws IOException
{
Dimension dim = kCanvas.getCanvasSize();
BufferedImage img;
if(format.equals("png"))
img = new BufferedImage(resol*dim.width, resol*dim.height,
BufferedImage.TYPE_INT_ARGB); // needed so we can get transparency in output
else
img = new BufferedImage(resol*dim.width, resol*dim.height,
BufferedImage.TYPE_INT_BGR); // this avoids color problems with JPEG and gives smaller files (?)
Graphics2D g2 = img.createGraphics();
g2.scale(resol, resol);
if(transparentBackground)
kCanvas.getEngine().setTransparentBackground();
kCanvas.paintCanvas(g2, dim, KinCanvas.QUALITY_BEST);
/* Easy enough to do in Keynote that it's not worth including here!
// Tasteful border - 1px, medium gray
if(!transparentBackground)
{
g2.setColor(new Color(0.5f, 0.5f, 0.5f, 1.0f));
g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawRect(0, 0, dim.width, dim.height);
}
*/
// This ensures we get high-quality JPEGs
if(format.equals("jpg"))
writeAtHighestQuality(img, format, outfile);
else
ImageIO.write(img, format, outfile);
}
//}}}
//{{{ writeAtHighestQuality
//##############################################################################
/**
* Saves the image in the specified format with the
* highest quality encoding available.
* A lot of this code was borrowed from a Java Tech Tip.
*/
static void writeAtHighestQuality(BufferedImage img, String format, File outfile)
throws IOException
{
ImageWriter bestWriter = null;
ImageWriteParam bestWriteParam = null;
float bestQual = 0;
for(Iterator iter = ImageIO.getImageWritersByFormatName(format); iter.hasNext(); )
{
ImageWriter iw = (ImageWriter) iter.next();
//System.err.println("New "+format+" writer ["+iw.getClass().getName()+"]:");
ImageWriteParam iwp = iw.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
float best = 0;
float values[] = iwp.getCompressionQualityValues();
for(int i = 0; i < values.length; i++)
{
//System.err.println(" "+values[i]);
best = Math.max(best, values[i]);
}
if(best > bestQual)
{
iwp.setCompressionQuality(best);
bestWriter = iw;
bestWriteParam = iwp;
bestQual = best;
}
}
if(bestWriter == null) return;
FileImageOutputStream output = new FileImageOutputStream(outfile);
bestWriter.setOutput(output);
IIOImage image = new IIOImage(img, null, null);
bestWriter.write(null, image, bestWriteParam);
// These two lines copied from javax.imageio.ImageIO.write()
// in hopes of writing out complete JPEGs under Windows
output.flush();
bestWriter.dispose();
output.close();
}
//}}}
//{{{ askExport
//##############################################################################
public void askExport()
{
// Auto-generate a file name
propertyChange(null);
// Show the Save dialog
if(JFileChooser.APPROVE_OPTION == chooser.showSaveDialog(kMain.getTopWindow()))
{
String fmt = getFormat();
javax.swing.filechooser.FileFilter filter = chooser.getFileFilter();
File f = chooser.getSelectedFile();
if(!filter.accept(f) &&
JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(kMain.getTopWindow(),
"This file has the wrong extension. Append '."+fmt+"' to the name?",
"Fix extension?", JOptionPane.YES_NO_OPTION))
{
f = new File(f+"."+fmt);
}
if(!f.exists() ||
JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(kMain.getTopWindow(),
"This file exists -- do you want to overwrite it?",
"Overwrite file?", JOptionPane.YES_NO_OPTION))
{
try { exportImage(kMain.getCanvas(), fmt, pngtFilter.equals(filter), kMain.getPrefs().getInt("imageExportMultiplier"), f); }
catch(IOException ex)
{
JOptionPane.showMessageDialog(kMain.getTopWindow(),
"An I/O error occurred while saving the file:\n"+ex.getMessage(),
"Sorry!", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace(SoftLog.err);
}
}
}
}
//}}}
//{{{ getFormat, propertyChange, run
//##################################################################################################
String getFormat()
{
String fmt;
javax.swing.filechooser.FileFilter filter = chooser.getFileFilter();
if(pngFilter.equals(filter)) fmt = "png";
else if(pngtFilter.equals(filter)) fmt = "png";
else if(jpgFilter.equals(filter)) fmt = "jpg";
else fmt = "jpg"; // shouldn't happen
return fmt;
}
public void propertyChange(PropertyChangeEvent ev)
{
if(ev == null
|| JFileChooser.FILE_FILTER_CHANGED_PROPERTY.equals(ev.getPropertyName())
|| JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(ev.getPropertyName()))
{
// Has to be done "asynchronously" or file name will be corrupted
SwingUtilities.invokeLater(this);
}
}
public void run()
{
String fmt = getFormat();
// Autogenerate an output name.
for(int i = 1; i < 1000; i++)
{
File f = new File(chooser.getCurrentDirectory(), "kingsnap"+i+"."+fmt);
if(!f.exists())
{
chooser.setSelectedFile(f);
break;
}
}
}
//}}}
//{{{ diagnostics
//##############################################################################
/** Writes diagnostic info about javax.imageio to SoftLog.err */
static public void diagnostics()
{
SoftLog.err.println("Can write the following formats:");
String[] types = ImageIO.getWriterMIMETypes();
for(int i = 0; i < types.length; i++)
SoftLog.err.println(" "+i+":\t"+types[i]);
for(int i = 0; i < types.length; i++)
{
SoftLog.err.println("Writers for "+types[i]+":");
for(Iterator iter = ImageIO.getImageWritersByMIMEType(types[i]); iter.hasNext(); )
SoftLog.err.println(" "+iter.next());
}
}
//}}}
//{{{ getToolsMenuItem, getHelpMenuItem, toString, onExport, isAppletSafe
//##################################################################################################
public JMenuItem getToolsMenuItem()
{
return new JMenuItem(new ReflectiveAction(this.toString()+"...", null, this, "onExport"));
}
public JMenuItem getHelpMenuItem()
{ return null; }
public String toString()
{ return "Image file (JPG, PNG)"; }
// This method is the target of reflection -- DO NOT CHANGE ITS NAME
public void onExport(ActionEvent ev)
{ this.askExport(); }
static public boolean isAppletSafe()
{ return false; }
//}}}
//{{{ empty_code_segment
//##############################################################################
//}}}
}//class
king-2.21.120420/king/1.x_src/king/tool/bondrot/ 0000755 0000000 0000000 00000000000 11744310054 017373 5 ustar root root king-2.21.120420/king/1.x_src/king/tool/bondrot/SuiteRotationTool.java 0000644 0000000 0000000 00000020615 11531212672 023712 0 ustar root root // (jEdit options) :folding=explicit:collapseFolds=1:
//{{{ Package, imports
package king.tool.bondrot;
import king.*;
import king.core.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import javax.swing.event.*;
import driftwood.gui.*;
import driftwood.r3.*;
//}}}
public class SuiteRotationTool extends BasicTool implements ChangeListener, ListSelectionListener, ActionListener, MageHypertextListener {
//{{{ Constants
//}}}
//{{{ Variable definitions
//##################################################################################################
AngleDial rotDial;
TablePane pane;
JList rotJList;
JList hypJList;
JTextField angField;
HyperRotParser hyptyp;
BondRotHandler handler;
BondRot oldRot = null;
//BondRot hyperRot = null;
boolean valueChanging = false;
ArrayList highlightedLists = null;
//}}}
//{{{ Constructor(s)
//##################################################################################################
/**
* Constructor
*/
public SuiteRotationTool(ToolBox tb) {
super(tb);
buildGUI();
}
//}}}
private void buildGUI() {
rotDial = new AngleDial();
rotJList = new JList();
hypJList = new JList();
angField = new JTextField("", 5);
angField.addActionListener(this);
pane = new TablePane();
pane.addCell(rotJList);
pane.addCell(rotDial);
pane.addCell(hypJList);
pane.newRow();
pane.skip();
pane.addCell(angField);
}
public void start() {
//buildGUI();
Collection brColl = kMain.getKinemage().getBondRots();
if (brColl.size() > 0) {
handler = new BondRotHandler(brColl);
//kMain.getTextWindow().addHypertextListener(this);
hyptyp = new HyperRotParser(kMain.getTextWindow().getText());
//hypJList.setListData(hyptyp.getHypList());
DefaultListModel hypModel = new DefaultListModel();
String[] stringArray = hyptyp.getHypList();
//System.out.println(stringArray.length);
for (int i = 0; i