/* * This file is part of LaTeXDraw. * Copyright (c) 2005-2017 Arnaud BLOUIN * LaTeXDraw 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 2 of the License, or (at your option) any later version. * LaTeXDraw is distributed 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. */ package net.sf.latexdraw.view.jfx; import java.util.List; import javafx.geometry.Point3D; import javafx.scene.paint.Color; import javafx.scene.shape.LineTo; import javafx.scene.shape.MoveTo; import javafx.scene.shape.Path; import javafx.scene.shape.PathElement; import net.sf.latexdraw.models.ShapeFactory; import net.sf.latexdraw.models.interfaces.shape.IPoint; import net.sf.latexdraw.ui.ScaleRuler; import net.sf.latexdraw.util.LNamespace; import net.sf.latexdraw.util.LPath; import net.sf.latexdraw.util.Unit; import net.sf.latexdraw.view.GridStyle; import net.sf.latexdraw.view.MagneticGrid; import net.sf.latexdraw.view.pst.PSTricksConstants; import org.eclipse.jdt.annotation.NonNull; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Implementation of a magnetic grid. * @author Arnaud Blouin */ class MagneticGridImpl extends Path implements MagneticGrid { /** The canvas that paints the grid. */ private final @NonNull Canvas canvas; /** Allows to know if the grid is magnetic or not. */ private boolean isMagnetic; /** defines the spacing between the lines of the grid. */ private int gridSpacing; /** The style of the grid. */ private GridStyle style; /** Defined if the canvas has been modified. */ private boolean modified; /** * Creates the magnetic grid. * @param canv The canvas in which the grid will work. * @throws NullPointerException if the given parameters are not valid. */ protected MagneticGridImpl(final @NonNull Canvas canv) { super(); modified = false; canvas = canv; reinitGrid(); setStroke(Color.BLACK); setStrokeWidth(0.3); canvas.zoomProperty().addListener((observable, oldValue, newValue) -> update()); } @Override public void update() { if(isDisable()) return; getElements().clear(); switch(style) { case STANDARD: double ppc = canvas.getPPCDrawing(); if(ScaleRuler.getUnit() == Unit.INCH) { ppc *= PSTricksConstants.INCH_VAL_CM; } // paintSubLines(getElements(), canvas.getLayoutBounds()); paintMainLines(getElements(), ppc); break; case CUSTOMISED: paintMainLines(getElements(), gridSpacing); break; case NONE: break; } } private void createLine(final List<PathElement> elts, final double x1, final double y1, final double x2, final double y2) { elts.add(new MoveTo(x1, y1)); elts.add(new LineTo(x2, y2)); } private void paintSubLines(final List<PathElement> elts) { double pixPerCm10 = canvas.getPPCDrawing() / 10d; if(ScaleRuler.getUnit() == Unit.INCH) { pixPerCm10 *= PSTricksConstants.INCH_VAL_CM; } if(Double.compare(pixPerCm10, 4d) > 0d) { // final double xMinclip = Math.floor(clip.getMinX() / pixPerCm10) * pixPerCm10 - clip.getMinX(); // final double yMinclip = Math.floor(clip.getMinY() / pixPerCm10) * pixPerCm10 - clip.getMinY(); // final double xMaxclip = clip.getMaxX(); // final double yMaxclip = clip.getMaxY(); // final double minX = clip.getMinX(); // final double minY = clip.getMinY(); // for(double i = pixPerCm10 - 1d + xMinclip + minX + canvas.getOrigin().getX() % pixPerCm10; i < xMaxclip; i += pixPerCm10) { // createLine(i, minY, i, yMaxclip); // } // // for(double i = pixPerCm10 - 1d + yMinclip + minY + canvas.getOrigin().getY() % pixPerCm10; i < yMaxclip; i += pixPerCm10) { // createLine(minX, i, xMaxclip, i); // } final double height = canvas.getPrefHeight(); final double width = canvas.getPrefWidth(); for(double i = 0; i<width; i+=pixPerCm10) { createLine(elts, i, 0, i, height); } for(double j = 0; j<height; j+=pixPerCm10) { createLine(elts, 0, j, width, j); } } } private void paintMainLines(final List<PathElement> elts, final double gap) { // final double zoom = canvas.getZoom(); // final double widthGap = clip.getWidth() - clip.getWidth() / zoom; // final double minX = -1d * clip.getMinX() + widthGap / 2d;// - (clip.getWidth() - clip.getWidth()*zoom); // final double maxX = minX + clip.getWidth() + widthGap + widthGap / 2d; // final double minY = -1d * clip.getMinY(); // final double maxY = minY + clip.getHeight(); final double height = canvas.getPrefHeight(); final double width = canvas.getPrefWidth(); for(double i = 0; i<width; i+=gap) { createLine(elts, i, 0, i, height); } for(double j = 0; j<height; j+=gap) { createLine(elts, 0, j, width, j); } // for(double i = minX - minX % gap, endX = maxX - maxX % gap + gap; i<endX; i+=gap) { // createLine(elts, i, minY, i, maxY); // } // // for(double j = minY - minY % gap, endY = maxY - maxY % gap + gap; j<endY; j+=gap) { // createLine(elts, minX, j, maxX, j); // } } @Override public IPoint getTransformedPointToGrid(final Point3D pt) { if(isMagnetic() && isGridDisplayed()) { final IPoint point = ShapeFactory.INST.createPoint(pt.getX(), pt.getY()); final double modulo = getMagneticGridGap(); double x = point.getX(); double y = point.getY(); int base = (int) ((int) (x / modulo) * modulo); if(x > modulo) { x %= (int) modulo; } double res = modulo - x; x = base; if(res < modulo / 2d) { x += modulo; } point.setX((int) x); base = (int) ((int) (point.getY() / modulo) * modulo); if(y > modulo) { y %= (int) modulo; } res = modulo - y; y = base; if(res < modulo / 2d) { y += modulo; } point.setY((int) y); return point; } return ShapeFactory.INST.createPoint(pt.getX(), pt.getY()); } @Override public double getMagneticGridGap() { double gap; if(isPersonalGrid()) gap = getGridSpacing(); else { final double ppc = canvas.getPPCDrawing(); gap = ScaleRuler.getUnit() == Unit.CM ? ppc / 10d : ppc * PSTricksConstants.INCH_VAL_CM / 10d; gap = gap - (int) gap > 0.5 ? (int) gap + 1d : (int) gap; } return gap; } @Override public void reinitGrid() { setGridStyle(GridStyle.CUSTOMISED); setGridSpacing(20); setMagnetic(true); } @Override public boolean isMagnetic() { return isMagnetic; } @Override public void setMagnetic(final boolean isMag) { if(isMagnetic != isMag) { isMagnetic = isMag; setModified(true); } } @Override public int getGridSpacing() { return gridSpacing; } @Override public void setGridSpacing(final int spacing) { if(spacing > 1 && gridSpacing != spacing) { gridSpacing = spacing; setModified(true); } } @Override public boolean isPersonalGrid() { return style == GridStyle.CUSTOMISED; } @Override public GridStyle getGridStyle() { return style; } @Override public void setGridStyle(final GridStyle gridStyle) { if(gridStyle != null && gridStyle != style) { style = gridStyle; setModified(true); } } @Override public boolean isGridDisplayed() { return style != GridStyle.NONE; } @Override public boolean isModified() { return modified; } @Override public void setModified(final boolean modif) { modified = modif; } @Override public void save(final boolean generalPreferences, final String nsURI, final Document document, final Element root) { if(document == null || root == null) return; final String ns = generalPreferences ? "" : LPath.INSTANCE.getNormaliseNamespaceURI(nsURI); //$NON-NLS-1$ Element elt = document.createElement(ns + LNamespace.XML_MAGNETIC_GRID_STYLE); elt.setTextContent(getGridStyle().toString()); root.appendChild(elt); elt = document.createElement(ns + LNamespace.XML_GRID_GAP); elt.setTextContent(String.valueOf(getGridSpacing())); root.appendChild(elt); elt = document.createElement(ns + LNamespace.XML_MAGNETIC_GRID); elt.setTextContent(String.valueOf(isMagnetic())); root.appendChild(elt); } @Override public void load(final boolean generalPreferences, final String nsURI, final Element meta) { final NodeList nl = meta.getChildNodes(); final String uri = nsURI == null ? "" : nsURI; //$NON-NLS-1$ Node node; String name; for(int i = 0, size = nl.getLength(); i < size; i++) { node = nl.item(i); // Must be a latexdraw tag. if(node != null && uri.equals(node.getNamespaceURI())) { name = node.getNodeName(); if(name.endsWith(LNamespace.XML_GRID_GAP)) { setGridSpacing(Integer.parseInt(node.getTextContent())); }else { if(name.endsWith(LNamespace.XML_MAGNETIC_GRID)) { setMagnetic(Boolean.parseBoolean(node.getTextContent())); }else { if(name.endsWith(LNamespace.XML_MAGNETIC_GRID_STYLE)) { setGridStyle(GridStyle.getStylefromName(node.getTextContent()).orElse(GridStyle.STANDARD)); } } } } } } }