/******************************************************************************* * Copyright 2010 Simon Mieth * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ /* Copyright 2005 Simon Mieth Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.kabeja.svg; import java.util.HashMap; import java.util.Iterator; import java.util.StringTokenizer; import org.kabeja.common.Block; import org.kabeja.common.Color; import org.kabeja.common.DraftEntity; import org.kabeja.common.Layer; import org.kabeja.common.LineWidth; import org.kabeja.common.Style; import org.kabeja.common.Type; import org.kabeja.common.Variable; import org.kabeja.entities.util.Utils; import org.kabeja.math.Bounds; import org.kabeja.math.TransformContext; import org.kabeja.objects.Dictionary; import org.kabeja.objects.Layout; import org.kabeja.svg.generators.SVGStyleGenerator; import org.kabeja.util.Constants; import org.kabeja.xml.AbstractSAXGenerator; import org.kabeja.xml.XMLConstants; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; public class SVGGenerator extends AbstractSAXGenerator { public final static String PROPERTY_MARGIN = "margin"; public final static String PROPERTY_STROKE_WIDTH = "stroke-width"; public final static String PROPERTY_STROKE_WIDTH_TYPE = "stroke-width-type"; public final static String PROPERTY_STROKE_WIDTH_TYPE_VALUE_PERCENT = "percent"; public final static String PROPERTY_STROKE_WIDTH_TYPE_VALUE_LINEWEIGHT = "lineweight"; public final static String PROPERTY_STROKE_WIDTH_TYPE_VALUE_LINEWIDTH = "linewidth"; public final static String PROPERTY_DOCUMENT_BOUNDS = "useBounds"; /** * This property defines the way of calculation/setup the bounds of the * Document. Possible values are: * <ul> * <li>kabeja: Bounds calculate on the geometries. (default)</li> * <li>paperspace: extracts the values of the limits from paperspace</li> * <li>modelspace: extracts the values of the limits from modelspace</li> * </ul> */ public final static String PROPERTY_DOCUMENT_BOUNDS_RULE = "bounds-rule"; public final static int PROPERTY_DOCUMENT_BOUNDS_RULE_KABEJA = 1; public final static int PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE = 2; public final static int PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE = 3; public final static String PROPERTY_DOCUMENT_BOUNDS_RULE_KABEJA_VALUE = "kabeja"; public final static String PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE_VALUE = "Paperspace"; public final static String PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE_LIMITS_VALUE = "Paperspace-Limits"; public final static String PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE_VALUE = "Modelspace"; public final static String PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE_LIMITS_VALUE = "Modelspace-Limits"; public final static String PROPERTY_DOCUMENT_OUTPUT_STYLE = "output-style"; public final static int PROPERTY_DOCUMENT_OUTPUT_STYLE_NOLAYOUT = 0; public final static int PROPERTY_DOCUMENT_OUTPUT_STYLE_LAYOUT = 1; public final static int PROPERTY_DOCUMENT_OUTPUT_STYLE_PLOTSETTING = 2; public final static String PROPERTY_DOCUMENT_OUTPUT_STYLE_LAYOUT_VALUE = "layout"; public final static String PROPERTY_DOCUMENT_OUTPUT_STYLE_PLOTSETTING_VALUE = "plotsetting"; public final static String PROPERTY_DOCUMENT_OUTPUT_STYLE_NAME = "output-style-name"; public final static String PROPERTY_WIDTH = "width"; public final static String PROPERTY_HEIGHT = "height"; public final static String PROPERTY_OVERFLOW = "svg-overflow"; public static final double DEFAULT_MARGIN_PERCENT = 0.0; public final static String SUPPORTED_SVG_VERSION = "1.0"; private boolean overflow = true; private boolean useLimits = false; private int boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE; private int outputStyle = PROPERTY_DOCUMENT_OUTPUT_STYLE_NOLAYOUT; private String marginSettings; private String outputStyleName = Constants.LAYOUT_DEFAULT_NAME; protected SVGSAXGeneratorManager manager; protected boolean useModelSpaceBlock = false; protected boolean usePaperSpaceBlock = false; protected void generate() throws SAXException { this.setupProperties(); this.generateSAX(); this.context = null; } protected void setupProperties() { if (this.context == null) { this.context = new HashMap<String,Object>(); } // setup the properties // the margin if (this.properties.containsKey(PROPERTY_MARGIN)) { this.marginSettings = this.properties.get(PROPERTY_MARGIN); } if (this.properties.containsKey(PROPERTY_OVERFLOW)) { this.overflow = Boolean.valueOf( this.properties.get(PROPERTY_OVERFLOW)) .booleanValue(); } // parse the line width property if (this.properties.containsKey(PROPERTY_STROKE_WIDTH)) { LineWidth lw = new LineWidth(); String strokeWidth = this.properties .get(PROPERTY_STROKE_WIDTH); lw.setValue(Double.parseDouble(strokeWidth)); String linewidthType = this.properties .get(PROPERTY_STROKE_WIDTH_TYPE); if (PROPERTY_STROKE_WIDTH_TYPE_VALUE_PERCENT.equals(linewidthType)) { lw.setType(LineWidth.TYPE_PERCENT); } else if (PROPERTY_STROKE_WIDTH_TYPE_VALUE_LINEWEIGHT .equals(linewidthType)) { lw.setType(LineWidth.TYPE_LINE_WEIGHT); } else { lw.setType(LineWidth.TYPE_LINE_WIDTH); } this.context.put(SVGContext.LINE_WIDTH, lw); // set to ignore the draft stroke width // this.context.put(SVGContext.DRAFT_STROKE_WIDTH_IGNORE, ""); } if (this.properties.containsKey(PROPERTY_DOCUMENT_BOUNDS_RULE)) { String value = ((String) this.properties .get(PROPERTY_DOCUMENT_BOUNDS_RULE)).trim(); if (value.equals(PROPERTY_DOCUMENT_BOUNDS_RULE_KABEJA_VALUE)) { // the new default is modelspace now this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE; this.useLimits = false; } else if (value .equals(PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE_VALUE)) { this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE; this.useLimits = false; } else if (value .equals(PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE_VALUE)) { this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE; this.useLimits = false; } else if (value .equals(PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE_LIMITS_VALUE)) { this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE; this.useLimits = true; } else if (value .equals(PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE_LIMITS_VALUE)) { this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE; this.useLimits = true; } } if (this.properties.containsKey(PROPERTY_DOCUMENT_OUTPUT_STYLE)) { String value = ((String) this.properties .get(PROPERTY_DOCUMENT_OUTPUT_STYLE)).trim().toLowerCase(); if (value.equals(PROPERTY_DOCUMENT_OUTPUT_STYLE_LAYOUT_VALUE)) { this.outputStyle = PROPERTY_DOCUMENT_OUTPUT_STYLE_LAYOUT; } else if (value .equals(PROPERTY_DOCUMENT_OUTPUT_STYLE_PLOTSETTING_VALUE)) { this.outputStyle = PROPERTY_DOCUMENT_OUTPUT_STYLE_PLOTSETTING; } if (this.properties .containsKey(PROPERTY_DOCUMENT_OUTPUT_STYLE_NAME)) { this.outputStyleName = ((String) this.properties .get(PROPERTY_DOCUMENT_OUTPUT_STYLE_NAME)).trim(); } } if (this.manager == null) { this.manager = new SVGSAXGeneratorManager(); } this.context.put(SVGContext.SVGSAXGENERATOR_MANAGER, manager); // setup some flags this.useModelSpaceBlock = false; this.usePaperSpaceBlock = false; } private void generateSAX() throws SAXException { try { this.handler.startDocument(); AttributesImpl attr = new AttributesImpl(); String viewport = ""; Bounds bounds = this.getBounds(); // set the height and width from properties or layout settings if (this.outputStyle == PROPERTY_DOCUMENT_OUTPUT_STYLE_NOLAYOUT) { if (this.properties.containsKey(PROPERTY_WIDTH)) { SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_WIDTH, (String) this.properties.get(PROPERTY_WIDTH)); } if (this.properties.containsKey(PROPERTY_HEIGHT)) { SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_HEIGHT, (String) this.properties.get(PROPERTY_HEIGHT)); } } else if (this.outputStyle == PROPERTY_DOCUMENT_OUTPUT_STYLE_LAYOUT) { // check for a layout and get the papersize Dictionary dict = (Dictionary) this.doc .getRootDictionary().getObjectByName( Constants.DICTIONARY_KEY_LAYOUT); if (dict != null) { Layout layout = (Layout) dict .getObjectByName(this.outputStyleName); if (layout != null) { Bounds paper = layout.getLimits(); // get the units of the paper String units = ""; switch (layout.getPaperUnit()) { case Constants.PAPER_UNIT_INCH: units = "in"; break; case Constants.PAPER_UNIT_MILLIMETER: units = "mm"; break; case Constants.PAPER_UNIT_PIXEL: units = "px"; break; } if (paper.isValid() && (paper.getWidth() > 0) && (paper.getHeight() > 0)) { SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_HEIGHT, "" + paper.getHeight() + units); SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_WIDTH, "" + paper.getWidth() + units); } // check for the bounds // Note this value could be false Bounds b = layout.getExtent(); if (b.isValid() && (b.getWidth() > 0) && (b.getHeight() > 0)) { bounds = b; } } } } // add the viewport // with margin // this is important otherwise in most cases // the SVG-Viewer will not show the content viewport = SVGUtils.formatNumberAttribute(bounds.getMinimumX()) + " " + SVGUtils .formatNumberAttribute((-1 * bounds.getMaximumY())) + " " + SVGUtils.formatNumberAttribute(bounds.getWidth()) + " " + SVGUtils.formatNumberAttribute(bounds.getHeight()); SVGUtils.addAttribute(attr, "viewBox", viewport); // set the default namespace SVGUtils.addAttribute(attr, "xmlns", SVGConstants.SVG_NAMESPACE); // the version of SVG we generate now SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_VERSION, SUPPORTED_SVG_VERSION); // the overflow if (this.overflow) { SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_OVERFLOW, SVGConstants.SVG_ATTRIBUTEVALUE_VISIBLE); } // add Kabeja namespace for additional kabeja output attr.addAttribute(SVGConstants.XMLNS_NAMESPACE, XMLConstants.KABEJA_NAMESPACE_PREFIX, "xmlns:" + XMLConstants.KABEJA_NAMESPACE_PREFIX, "CDATA", XMLConstants.KABEJA_NAMESPACE); SVGUtils.startElement(this.handler, SVGConstants.SVG_ROOT, attr); // the blocks as symbol in the defs-section of SVG attr = new AttributesImpl(); SVGUtils.startElement(this.handler, SVGConstants.SVG_DEFS, attr); // set the context context.put(SVGContext.DRAFT_BOUNDS, bounds); double dotLength = 0.0; if (bounds.getWidth() > bounds.getHeight()) { dotLength = bounds.getHeight() * SVGConstants.DEFAULT_STROKE_WIDTH_PERCENT; } else { dotLength = bounds.getWidth() * SVGConstants.DEFAULT_STROKE_WIDTH_PERCENT; } context.put(SVGContext.DOT_LENGTH, new Double(dotLength)); for(Block block :doc.getBlocks()){ this.blockToSAX(block, null); } // maybe there is a fontdescription available from DXFStyle for(Style style:doc.getStyles()){ SVGStyleGenerator.toSAX(handler, context, style); } SVGUtils.endElement(handler, SVGConstants.SVG_DEFS); // the draft attr = new AttributesImpl(); SVGUtils.addAttribute(attr, SVGConstants.XML_ID, "draft"); // the globale coordinate system transformation // note: DXF has the y-axis positiv from bottom to top // SVG has the y-axis positiv from top to bottom SVGUtils.addAttribute(attr, "transform", "matrix(1 0 0 -1 0 0)"); // the stroke-width if (this.context.containsKey(SVGContext.LINE_WIDTH)) { // the user has setup a stroke-width SVGUtils .addAttribute( attr, SVGConstants.SVG_ATTRIBUTE_STROKE_WITDH, SVGUtils .lineWidthToStrokeWidth((LineWidth) this.context .get(SVGContext.LINE_WIDTH))); } else { double sw = (bounds.getWidth() + bounds.getHeight()) / 2 * SVGConstants.DEFAULT_STROKE_WIDTH_PERCENT; double defaultSW = ((double) Constants.ENVIRONMENT_VARIABLE_LWDEFAULT) / 100.0; if (sw > defaultSW) { sw = defaultSW; } LineWidth lw = new LineWidth(); lw.setType(LineWidth.TYPE_LINE_WIDTH); lw.setValue(sw); SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_STROKE_WITDH, SVGUtils .lineWidthToStrokeWidth(lw)); this.context.put(SVGContext.LINE_WIDTH, lw); } SVGUtils.startElement(handler, SVGConstants.SVG_GROUP, attr); if (this.useModelSpaceBlock) { Block block = this.doc .getBlock(Constants.BLOCK_MODELSPACE); this.blockToSAX(block, null); } else if (this.usePaperSpaceBlock) { Block block = this.doc .getBlock(Constants.BLOCK_PAPERSPACE); this.blockToSAX(block, null); } else { // the layers as container g-elements Iterator<Layer> i = Utils.sortedLayersByZIndexIterator(this.doc .getLayers().iterator()); while (i.hasNext()) { Layer layer = (Layer) i.next(); if (this.boundsRule == PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE) { // out put only the paper space maybe with views to // model space this.layerToSAX(layer, false); } else { // output only the model space -> the default this.layerToSAX(layer, true); } } } SVGUtils.endElement(handler, SVGConstants.SVG_GROUP); SVGUtils.endElement(handler, SVGConstants.SVG_ROOT); handler.endDocument(); } catch (SAXException e) { e.printStackTrace(); } } protected void blockToSAX(Block block, TransformContext transformContext) throws SAXException { AttributesImpl attr = new AttributesImpl(); // SVGUtils.addAttribute(attr, SVGConstants.XML_ID, SVGUtils // .validateID(block.getName())); SVGUtils.addAttribute(attr, SVGConstants.XML_ID, SVGUtils .toValidateID(block.getID())); SVGUtils.startElement(handler, SVGConstants.SVG_GROUP, attr); for( DraftEntity entity:block.getEntities()){ try { SVGSAXGenerator gen = manager.getSVGGenerator(entity.getType().getHandle()); gen.toSAX(handler, this.context, entity, transformContext); } catch (SVGGenerationException e) { e.printStackTrace(); } } SVGUtils.endElement(handler, SVGConstants.SVG_GROUP); } /** * Returns the margin-array where: * <ul> * <li>0 ->top margin</li> * <li>1 ->right margin</li> * <li>2 ->bottom margin</li> * <li>3 ->left margin</li> * </ul> * * @param bounds * @return */ protected double[] getMargin(Bounds bounds) { double[] margin = new double[4]; if (this.marginSettings != null) { StringTokenizer st = new StringTokenizer(this.marginSettings); int count = st.countTokens(); switch (count) { case 4: for (int i = 0; i < count; i++) { String m = st.nextToken().trim(); if (m.endsWith("%")) { m = m.substring(0, m.length() - 1); if ((i == 0) && (i == 2)) { margin[i] = (Double.parseDouble(m) / 100) * bounds.getHeight(); } else { margin[i] = (Double.parseDouble(m) / 100) * bounds.getWidth(); } } else { margin[i] = Double.parseDouble(m); } } return margin; case 1: String m = st.nextToken().trim(); if (m.endsWith("%")) { m = m.substring(0, m.length() - 1); } margin[0] = Double.parseDouble(m); margin[1] = margin[2] = margin[3] = margin[0]; return margin; } } margin[0] = bounds.getHeight() * (DEFAULT_MARGIN_PERCENT / 100); margin[2] = margin[0]; margin[1] = bounds.getWidth() * (DEFAULT_MARGIN_PERCENT / 100); margin[3] = margin[1]; return margin; } protected Bounds getBounds() { Bounds bounds = null; if (this.boundsRule == PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE) { // first the user based limits of the paperspace bounds = new Bounds(); if (this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_PEXTMAX) && this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_PEXTMIN) && useLimits) { Variable min = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_PEXTMIN); Variable max = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_PEXTMAX); bounds.setMinimumX(min.getDoubleValue("10")); bounds.setMinimumY(min.getDoubleValue("20")); bounds.setMaximumX(max.getDoubleValue("10")); bounds.setMaximumY(max.getDoubleValue("20")); } if ((!bounds.isValid() || (bounds.getWidth() == 0.0) || (bounds .getHeight() == 0.0)) && this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_PLIMMIN) && this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_PLIMMAX) && useLimits) { Variable min = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_PLIMMIN); Variable max = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_PLIMMAX); bounds.setMinimumX(min.getDoubleValue("10")); bounds.setMinimumY(min.getDoubleValue("20")); bounds.setMaximumX(max.getDoubleValue("10")); bounds.setMaximumY(max.getDoubleValue("20")); } if (!bounds.isValid() || (bounds.getWidth() == 0.0) || (bounds.getHeight() == 0.0)) { // get bounds only from paper space entities bounds = this.doc.getBounds(false); } } else if (this.boundsRule == PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE) { // first the user based limits of the modelspace bounds = new Bounds(); if (this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_EXTMIN) && this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_EXTMAX) && useLimits) { Variable min = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_EXTMIN); Variable max = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_EXTMAX); bounds.setMinimumX(min.getDoubleValue("10")); bounds.setMinimumY(min.getDoubleValue("20")); bounds.setMaximumX(max.getDoubleValue("10")); bounds.setMaximumY(max.getDoubleValue("20")); } if ((!bounds.isValid() || (bounds.getWidth() == 0.0) || (bounds .getHeight() == 0.0)) && this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_LIMMIN) && this.doc.getHeader().hasVariable( Constants.HEADER_VARIABLE_LIMMAX) && useLimits) { Variable min = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_LIMMIN); Variable max = this.doc.getHeader().getVariable( Constants.HEADER_VARIABLE_LIMMAX); bounds.setMinimumX(min.getDoubleValue("10")); bounds.setMinimumY(min.getDoubleValue("20")); bounds.setMaximumX(max.getDoubleValue("10")); bounds.setMaximumY(max.getDoubleValue("20")); } if (!bounds.isValid() || (bounds.getWidth() == 0.0) || (bounds.getHeight() == 0.0)) { // get bounds only from model space entities bounds = this.doc.getBounds(true); } } if ((bounds == null) || !bounds.isValid() || (bounds.getWidth() == 0.0) || (bounds.getHeight() == 0.0)) { if (this.boundsRule == PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE) { bounds = this.doc.getBounds(true); this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_MODELSPACE; } else { bounds = this.doc.getBounds(false); this.boundsRule = PROPERTY_DOCUMENT_BOUNDS_RULE_PAPERSPACE; } } // check for model space block if (!bounds.isValid()) { Block block = this.doc .getBlock(Constants.BLOCK_MODELSPACE); if (block != null) { bounds = block.getBounds(); this.useModelSpaceBlock = true; } } // check for the paper space block if (!bounds.isValid()) { Block block = this.doc .getBlock(Constants.BLOCK_PAPERSPACE); if (block != null) { bounds = block.getBounds(); this.usePaperSpaceBlock = true; } } // last check if nothing is correct // this happens on empty drafts // or only drafts with blocks if (!bounds.isValid()) { bounds.addToBounds(0, 0, 0); } // set a margin double[] margin = this.getMargin(bounds); bounds.setMinimumX(bounds.getMinimumX() - margin[3]); bounds.setMaximumX(bounds.getMaximumX() + margin[1]); bounds.setMinimumY(bounds.getMinimumY() - margin[2]); bounds.setMaximumY(bounds.getMaximumY() + margin[0]); return bounds; } public void setSVGSAXGeneratorManager(SVGSAXGeneratorManager manager) { this.manager = manager; } protected void layerToSAX(Layer layer, boolean onModelspace) throws SAXException { AttributesImpl attr = new AttributesImpl(); attr.addAttribute(XMLConstants.KABEJA_NAMESPACE, XMLConstants.KABEJA_ATTRIBUTE_LAYER_NAME, XMLConstants.KABEJA_QNAME_ATTRIBUTE_LAYER_NAME, "CDATA", layer .getName()); // the layer name may not be a valid ID, so we omit this part now // SVGUtils.addAttribute(attr, SVGConstants.XML_ID, SVGUtils // .validateID(layer.getName())); SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_COLOR, Color.getRGBString(Math.abs(layer.getColor()))); SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_STROKE, SVGConstants.SVG_ATTRIBUTE_VALUE_CURRENTCOLOR); SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_FILL, SVGConstants.SVG_ATTRIBUTE_FILL_VALUE_NONE); if (!layer.isVisible() && onModelspace) { SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_VISIBILITY, SVGConstants.SVG_ATTRIBUTE_VISIBILITY_VALUE_HIDDEN); } SVGUtils.addStrokeDashArrayAttribute(attr, layer.getLineType()); // the stroke-width int lineWeight = layer.getLineWeight(); // the stroke-width LineWidth lw = new LineWidth(); if ((lineWeight > 0) && !context.containsKey(SVGContext.DRAFT_STROKE_WIDTH_IGNORE)) { lw.setType(LineWidth.TYPE_LINE_WEIGHT); lw.setValue(lineWeight); } else { lw = (LineWidth) context.get(SVGContext.LINE_WIDTH); } SVGUtils.addAttribute(attr, SVGConstants.SVG_ATTRIBUTE_STROKE_WITDH, SVGUtils.lineWidthToStrokeWidth(lw)); context.put(SVGContext.LAYER_STROKE_WIDTH, lw); SVGUtils.startElement(handler, SVGConstants.SVG_GROUP, attr); SVGUtils.startElement(handler, SVGConstants.SVG_TITLE, new AttributesImpl()); SVGUtils.characters(handler, layer.getName()); SVGUtils.endElement(handler, SVGConstants.SVG_TITLE); for( Type<? extends DraftEntity> type:layer.getEntityTypes()){ try { SVGSAXGenerator gen = this.manager.getSVGGenerator(type.getHandle()); for( DraftEntity entity:layer.getEntitiesByType(type)){ boolean v = entity.isVisibile(); entity.setVisibile(!layer.isFrozen()); if (!onModelspace) { entity.setVisibile(layer.isVisible()); } if ((onModelspace && entity.isModelSpace()) || (!onModelspace && !entity.isModelSpace())) { gen.toSAX(handler, context, entity, null); } // restore back the flag entity.setVisibile(v); } } catch (SVGGenerationException e) { e.printStackTrace(); } } SVGUtils.endElement(handler, SVGConstants.SVG_GROUP); } }