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; } }