package net.sourceforge.fidocadj.primitives;
import java.io.*;
import java.util.*;
import net.sourceforge.fidocadj.export.*;
import net.sourceforge.fidocadj.geom.*;
import net.sourceforge.fidocadj.globals.*;
import net.sourceforge.fidocadj.graphic.*;
/** Class to handle the Connection primitive.
<pre>
This file is part of FidoCadJ.
FidoCadJ is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FidoCadJ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FidoCadJ. If not,
@see <a href=http://www.gnu.org/licenses/>http://www.gnu.org/licenses/</a>.
Copyright 2007-2014 by Davide Bucci
</pre>
@author Davide Bucci
*/
public final class PrimitiveConnection
extends GraphicPrimitive
{
// A connection is defined by one points.
// We take into account the optional Name and Value text tags.
static final int N_POINTS=3;
// Those are data which are kept for the fast redraw of this primitive.
// Basically, they are calculated once and then used as much as possible
// without having to calculate everything from scratch.
private int x1, y1, xa1, ya1, ni;
private double nn;
private float w;
/** Gets the number of control points used.
@return the number of points used by the primitive
*/
public int getControlPointNumber()
{
return N_POINTS;
}
/** Constructor.
@param f the name of the font for attached text.
@param size the size of the font for attached text.
*/
public PrimitiveConnection(String f, int size)
{
super();
initPrimitive(-1, f, size);
}
/** Create a connection in the given point.
@param x the x coordinate (logical unit) of the connection.
@param y the y coordinate (logical unit) of the connection.
@param layer the layer to be used.
@param f the name of the font for attached text.
@param size the size of the font for attached text.
*/
public PrimitiveConnection(int x, int y, int layer, String f, int size)
{
super();
initPrimitive(-1, f, size);
virtualPoint[0].x=x;
virtualPoint[0].y=y;
virtualPoint[getNameVirtualPointNumber()].x=x+5;
virtualPoint[getNameVirtualPointNumber()].y=y+5;
virtualPoint[getValueVirtualPointNumber()].x=x+5;
virtualPoint[getValueVirtualPointNumber()].y=y+10;
setLayer(layer);
}
/** Draw the graphic primitive on the given graphic context.
@param g the graphic context in which the primitive should be drawn.
@param coordSys the graphic coordinates system to be applied.
@param layerV the layer description.
*/
public void draw(GraphicsInterface g, MapCoordinates coordSys,
Vector layerV)
{
if(!selectLayer(g,layerV))
return;
drawText(g, coordSys, layerV, -1);
if (changed) {
changed=false;
/* in the Connection primitive, the virtual point represents
the position of the center of the circle to be drawn. */
x1=virtualPoint[0].x;
y1=virtualPoint[0].y;
nn=Math.abs(coordSys.mapXr(0,0)-
coordSys.mapXr(10,10))*Globals.diameterConnection/10.0;
// a little boost for small zooms :-)
if (nn<2.0) {
nn=(int)(Math.abs(coordSys.mapXr(0,0)-
coordSys.mapXr(20,20))*Globals.diameterConnection/12);
}
xa1=(int)Math.round(coordSys.mapX(x1,y1)-nn/2.0);
ya1=(int)Math.round(coordSys.mapY(x1,y1)-nn/2.0);
ni=(int)Math.round(nn);
// Make sure that something is drawn even for very small
// connections
if(ni==0)
ni=1;
w = (float)(Globals.lineWidth*coordSys.getXMagnitude());
if (w<D_MIN) w=D_MIN;
}
if(!g.hitClip(xa1, ya1, ni, ni))
return;
g.applyStroke(w, 0);
// When the circle is very small, it is better to set a single pixel
// than trying to fill the oval.
if(ni>1)
g.fillOval(xa1, ya1, ni, ni);
else
g.fillRect(xa1, ya1, ni, ni);
}
/** Parse a token array and store the graphic data for a given primitive
Obviously, that routine should be called *after* having recognized
that the called primitive is correct.
That routine also sets the current layer.
@param tokens the tokens to be processed. tokens[0] should be the
command of the actual primitive.
@param N the number of tokens present in the array
@throws IOException if the arguments are incorrect or the primitive
is invalid.
*/
public void parseTokens(String[] tokens, int N)
throws IOException
{
changed=true;
if (tokens[0].equals("SA")) { // Connection
if (N<3) {
IOException E=new IOException("bad arguments on SA");
throw E;
}
// Load the points in the virtual points associated to the
// current primitive.
int x1 = virtualPoint[0].x=Integer.parseInt(tokens[1]);
int y1 = virtualPoint[0].y=Integer.parseInt(tokens[2]);
virtualPoint[getNameVirtualPointNumber()].x=x1+5;
virtualPoint[getNameVirtualPointNumber()].y=y1+5;
virtualPoint[getValueVirtualPointNumber()].x=x1+5;
virtualPoint[getValueVirtualPointNumber()].y=y1+10;
if(N>3) parseLayer(tokens[3]);
} else {
IOException E=new IOException("Invalid primitive:"+
" programming error?");
throw E;
}
}
/** Gets the distance (in primitive's coordinates space) between a
given point and the primitive.
When it is reasonable, the behaviour can be binary (polygons,
ovals...). In other cases (lines, points), it can be proportional.
@param px the x coordinate of the given point.
@param py the y coordinate of the given point.
@return the distance in logical units.
*/
public int getDistanceToPoint(int px, int py)
{
// Here we check if the given point lies inside the text areas
if(checkText(px, py))
return 0;
// If not, we check for the distance with the connection center.
return GeometricDistances.pointToPoint(
virtualPoint[0].x,virtualPoint[0].y,
px,py)-1;
}
/** Obtain a string command descripion of the primitive.
@param extensions true if FidoCadJ extensions to the old FidoCAD format
should be active.
@return the FIDOCAD command line.
*/
public String toString(boolean extensions)
{
StringBuffer s=new StringBuffer(100);
s.append("SA ");
s.append(virtualPoint[0].x);
s.append(" ");
s.append(virtualPoint[0].y);
s.append(" ");
s.append(getLayer());
s.append("\n");
s.append(saveText(extensions));
return s.toString();
}
/** Export the primitive on a vector graphic format.
@param exp the export interface to employ.
@param cs the coordinate mapping to employ.
@throws IOException if a problem occurs, such as it is impossible to
write on the output file.
*/
public void export(ExportInterface exp, MapCoordinates cs)
throws IOException
{
exportText(exp, cs, -1);
exp.exportConnection(cs.mapX(virtualPoint[0].x,virtualPoint[0].y),
cs.mapY(virtualPoint[0].x,virtualPoint[0].y), getLayer(),
Globals.diameterConnection*cs.getXMagnitude());
}
/** Get the number of the virtual point associated to the Name property
@return the number of the virtual point associated to the Name property
*/
public int getNameVirtualPointNumber()
{
return 1;
}
/** Get the number of the virtual point associated to the Value property
@return the number of the virtual point associated to the Value property
*/
public int getValueVirtualPointNumber()
{
return 2;
}
}