package net.sourceforge.fidocadj.circuit.views;
import java.util.*;
import net.sourceforge.fidocadj.circuit.model.*;
import net.sourceforge.fidocadj.geom.*;
import net.sourceforge.fidocadj.globals.*;
import net.sourceforge.fidocadj.layers.*;
import net.sourceforge.fidocadj.primitives.*;
import net.sourceforge.fidocadj.graphic.*;
/** Drawing: draws the FidoCadJ drawing. This is a view of the drawing.
<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-2016 by Davide Bucci
</pre>
*/
public class Drawing
{
private final DrawingModel dmp;
// True if the drawing needs holes. This implies that the redrawing
// step must include a cycle at the end to draw all holes.
private boolean needHoles;
// *********** CACHE *************
// Here are some counters and local variables. We made them class members
// to ensure that their place is reserved in memory and we do not need
// some time expensive allocations, since speed is important in the draw
// operation (used in draw).
private double oZ, oX, oY, oO;
private GraphicPrimitive gg;
private int i_index;
private int j_index;
/** Create a drawing view.
@param pp the model to which the view will be associated.
*/
public Drawing (DrawingModel pp)
{
dmp=pp;
}
/** Draw the handles of all selected primitives
@param gi the graphic context to be used.
@param cs the coordinate mapping system to employ.
*/
public void drawSelectedHandles(GraphicsInterface gi, MapCoordinates cs)
{
int i;
for (GraphicPrimitive gp : dmp.getPrimitiveVector()) {
if(gp.getSelected())
gp.drawHandles(gi, cs);
}
}
/** Draw the current drawing.
This code is rather critical. Do not touch it unless you know very
precisely what you are doing.
@param G the graphic context in which the drawing should be drawn.
@param cs the coordinate mapping to be used.
*/
public void draw(GraphicsInterface G, MapCoordinates cs)
{
if(cs==null) {
System.err.println(
"DrawingModel.draw: ouch... cs not initialized :-(");
return;
}
synchronized (this) {
// At first, we check if the current view has changed.
if(dmp.changed || oZ!=cs.getXMagnitude() || oX!=cs.getXCenter() ||
oY!=cs.getYCenter() || oO!=cs.getOrientation())
{
oZ=cs.getXMagnitude();
oX=cs.getXCenter();
oY=cs.getYCenter();
oO=cs.getOrientation();
dmp.changed = false;
// Here we force for a global refresh of graphic data at the
// primitive level.
for (GraphicPrimitive gp : dmp.getPrimitiveVector())
gp.setChanged(true);
if (!dmp.drawOnlyPads)
cs.resetMinMax();
}
needHoles=dmp.drawOnlyPads;
/* First possibility: we need to draw only one layer (for example
in a macro). This is indicated by the fact that drawOnlyLayer
is non negative.
*/
if(dmp.drawOnlyLayer>=0 && !dmp.drawOnlyPads){
// At first, we check if the layer is effectively used in the
// drawing. If not, we exit directly.
if(!dmp.layersUsed[dmp.drawOnlyLayer])
return;
drawPrimitives(dmp.drawOnlyLayer, G, cs);
return;
} else if (!dmp.drawOnlyPads) {
// If we want to draw all layers, we need to process with order.
for(j_index=0;j_index<LayerDesc.MAX_LAYERS; ++j_index) {
if(!dmp.layersUsed[j_index])
continue;
drawPrimitives(j_index, G,cs);
}
}
// Draw in a second time only the PCB pads, in order to ensure that
// the drills are always open.
if(needHoles) {
for (i_index=0; i_index<dmp.getPrimitiveVector().size();
++i_index){
// We will process only primitive which require holes (pads
// as well as macros containing pads).
if ((gg=(GraphicPrimitive)dmp.getPrimitiveVector().
get(i_index)).needsHoles())
{
gg.setDrawOnlyPads(true);
gg.draw(G, cs, dmp.layerV);
gg.setDrawOnlyPads(false);
}
}
}
}
}
/** Returns true if there is the need of drawing holes in the actual
drawing.
@return true if holes are needed.
*/
public final boolean getNeedHoles()
{
return needHoles;
}
/** Draws all the primitives and macros contained in the specified layer.
This function is used mainly by the draw member.
@param j_index the layer to be considered.
@param G the graphic context in which to draw.
*/
private void drawPrimitives(int j_index, GraphicsInterface graphic,
MapCoordinates cs)
{
// Here we process all the primitives, one by one!
for (GraphicPrimitive gg : dmp.getPrimitiveVector()) {
// Layers are ordered. This improves the redrawing speed.
if (j_index>0 && gg.layer>j_index) {
break;
}
// Process a particular primitive if it is in the layer
// being processed.
if(gg.containsLayer(j_index)) {
gg.setDrawOnlyLayer(j_index);
gg.draw(graphic, cs, dmp.layerV);
}
if(gg.needsHoles())
needHoles=true;
}
}
}