package net.sf.openrocket.gui.print.visitor; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.pdf.PdfWriter; import net.sf.openrocket.gui.print.AbstractPrintable; import net.sf.openrocket.gui.print.PrintableCenteringRing; import net.sf.openrocket.rocketcomponent.CenteringRing; import net.sf.openrocket.rocketcomponent.InnerTube; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.ArrayList; import java.util.List; import java.util.Set; /** * A strategy for printing a centering ring to iText. */ public class CenteringRingStrategy extends AbstractPrintStrategy<Void> { /** * Constructor. * * @param doc The iText document * @param theWriter The direct iText writer * @param theStagesToVisit The stages to be visited by this strategy */ public CenteringRingStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit, PageFitPrintStrategy pageFit) { super(doc, pageFit, theWriter, theStagesToVisit); document = doc; writer = theWriter; stages = theStagesToVisit; pageFitPrint = pageFit; } /** * Recurse through the given rocket component. * * @param theRc an array of rocket components; all children will be visited recursively */ protected Void goDeep(final List<RocketComponent> theRc) { for (RocketComponent rocketComponent : theRc) { if (rocketComponent instanceof CenteringRing) { render((CenteringRing) rocketComponent); } else if (rocketComponent.getChildCount() > 0) { goDeep(rocketComponent.getChildren()); } } return null; } /** * Find the inner tubes that are physically supported by the given centering ring. Note that this only looks for * motor mount tubes that are siblings to the centering ring. * * @param rc the centering ring, for which all motor mount tubes that run through it are located. * * @return the list of tubes found */ private List<InnerTube> findMotorMount(CenteringRing rc) { RocketComponent parent = rc.getParent(); List<RocketComponent> siblings = parent.getChildren(); List<InnerTube> mounts = new ArrayList<InnerTube>(); for (RocketComponent rocketComponents : siblings) { if (rocketComponents != rc) { if (rocketComponents instanceof InnerTube) { InnerTube it = (InnerTube) rocketComponents; if (overlaps(rc, it)) { mounts.add(it); } } } } return mounts; } /** * Determine if the centering ring physically overlaps with the inner tube. * * @param one the centering ring * @param two the inner body tube * * @return true if the two physically intersect, from which we infer that the centering ring supports the tube */ private boolean overlaps(CenteringRing one, InnerTube two) { final double crTopPosition = one.asPositionValue(RocketComponent.Position.ABSOLUTE, one.getParent()); final double mmTopPosition = two.asPositionValue(RocketComponent.Position.ABSOLUTE, two.getParent()); final double crBottomPosition = one.getLength() + crTopPosition; final double mmBottomPosition = two.getLength() + mmTopPosition; if (crTopPosition >= mmTopPosition && crTopPosition <= mmBottomPosition) { return true; } if (crBottomPosition >= mmTopPosition && crBottomPosition <= mmBottomPosition) { return true; } return false; } /** * The core behavior of this strategy. * * @param component the object to extract info about; a graphical image of the centering ring shape is drawn to the * document */ private void render(final CenteringRing component) { try { AbstractPrintable pfs; pfs = PrintableCenteringRing.create(component, findMotorMount(component)); render(pfs); } catch (DocumentException e) { log.error("Could not render the centering ring.", e); } } }