Index: org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.app/org.gvsig.vectorediting.offset.app.mainplugin/src/main/resources-plugin/i18n/text.properties
===================================================================
--- org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.app/org.gvsig.vectorediting.offset.app.mainplugin/src/main/resources-plugin/i18n/text.properties	(revision 2872)
+++ org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.app/org.gvsig.vectorediting.offset.app.mainplugin/src/main/resources-plugin/i18n/text.properties	(revision 2873)
@@ -12,4 +12,14 @@
 _right=Derecho
 _short_left=I
 _short_right=D
-_side=Lado
\ No newline at end of file
+_side=Lado
+side=Lado
+_round=Redondeado
+_mitre=Inglete
+_bevel=Bisel
+_short_round=R
+_short_mitre=I
+_short_bevel=B
+_join_style=Estilo de uni\u00f3n
+joinStyle=Estilo de uni\u00f3n
+equidistant_offsets=Paralelas equidistantes
\ No newline at end of file
Index: org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.app/org.gvsig.vectorediting.offset.app.mainplugin/src/main/resources-plugin/i18n/text_en.properties
===================================================================
--- org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.app/org.gvsig.vectorediting.offset.app.mainplugin/src/main/resources-plugin/i18n/text_en.properties	(revision 2872)
+++ org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.app/org.gvsig.vectorediting.offset.app.mainplugin/src/main/resources-plugin/i18n/text_en.properties	(revision 2873)
@@ -12,4 +12,14 @@
 _right=Right
 _short_left=L
 _short_right=R
-_side=Side
\ No newline at end of file
+_side=Side
+side=Side
+_round=Round
+_mitre=Mitre
+_bevel=Bevel
+_short_round=R
+_short_mitre=M
+_short_bevel=B
+_join_style=Join style
+joinStyle=Join style
+equidistant_offsets=Equidistantes offsets
\ No newline at end of file
Index: org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.lib/org.gvsig.vectorediting.offset.lib.prov/org.gvsig.vectorediting.offset.lib.prov.offset/pom.xml
===================================================================
--- org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.lib/org.gvsig.vectorediting.offset.lib.prov/org.gvsig.vectorediting.offset.lib.prov.offset/pom.xml	(revision 2872)
+++ org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.lib/org.gvsig.vectorediting.offset.lib.prov/org.gvsig.vectorediting.offset.lib.prov.offset/pom.xml	(revision 2873)
@@ -21,5 +21,9 @@
       <groupId>org.gvsig</groupId>
       <artifactId>org.gvsig.vectorediting.lib.spi</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.gvsig</groupId>
+      <artifactId>org.gvsig.symbology.lib.api</artifactId>
+    </dependency>
   </dependencies>
 </project>
Index: org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.lib/org.gvsig.vectorediting.offset.lib.prov/org.gvsig.vectorediting.offset.lib.prov.offset/src/main/java/org/gvsig/vectorediting/offset/lib/prov/offset/OffsetEditingProvider.java
===================================================================
--- org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.lib/org.gvsig.vectorediting.offset.lib.prov/org.gvsig.vectorediting.offset.lib.prov.offset/src/main/java/org/gvsig/vectorediting/offset/lib/prov/offset/OffsetEditingProvider.java	(revision 2872)
+++ org.gvsig.vectorediting.offset/trunk/org.gvsig.vectorediting.offset/org.gvsig.vectorediting.offset.lib/org.gvsig.vectorediting.offset.lib.prov/org.gvsig.vectorediting.offset.lib.prov.offset/src/main/java/org/gvsig/vectorediting/offset/lib/prov/offset/OffsetEditingProvider.java	(revision 2873)
@@ -23,9 +23,9 @@
  */
 package org.gvsig.vectorediting.offset.lib.prov.offset;
 
+import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
@@ -35,9 +35,11 @@
 import org.gvsig.fmap.dal.feature.FeatureSelection;
 import org.gvsig.fmap.dal.feature.FeatureStore;
 import org.gvsig.fmap.geom.Geometry;
+import static org.gvsig.fmap.geom.Geometry.JOIN_STYLE_ROUND;
 import org.gvsig.fmap.geom.GeometryException;
 import org.gvsig.fmap.geom.GeometryLocator;
 import org.gvsig.fmap.geom.GeometryManager;
+import org.gvsig.fmap.geom.GeometryUtils;
 import org.gvsig.fmap.geom.aggregate.Aggregate;
 import org.gvsig.fmap.geom.aggregate.MultiCurve;
 import org.gvsig.fmap.geom.aggregate.MultiPoint;
@@ -58,6 +60,9 @@
 import org.gvsig.fmap.geom.primitive.Spline;
 import org.gvsig.fmap.geom.primitive.Surface;
 import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
+import org.gvsig.symbology.SymbologyLocator;
+import org.gvsig.symbology.SymbologyManager;
+import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text.ISimpleTextSymbol;
 import org.gvsig.tools.ToolsLocator;
 import org.gvsig.tools.dataTypes.DataTypes;
 import org.gvsig.tools.dispose.DisposableIterator;
@@ -72,6 +77,7 @@
 import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
 import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
 import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
+import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException;
 import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
 import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
 import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
@@ -97,13 +103,30 @@
 
     private static final String SHORT_RIGHT = "_short_right";
 
+    private static final String JOIN_STYLE = "_join_style";
 
+    private static final String ROUND = "_round";
+
+    private static final String MITRE = "_mitre";
+    
+    private static final String BEVEL = "_bevel";
+
+    private static final String SHORT_ROUND = "_short_round";
+
+    private static final String SHORT_MITRE = "_short_mitre";
+    
+    private static final String SHORT_BEVEL = "_short_bevel";
+
     private final EditingServiceParameter selectionParameter;
 
     private final EditingServiceParameter offsetParameter;
 
     private final EditingServiceParameter sideParameter;
 
+    private final DefaultEditingServiceParameter joinStyleParameter;
+    
+    private final EditingServiceParameter equidistantOffsets;
+    
     private final EditingServiceParameter deleteOriginalGeometriesParameter;
 
 //    private boolean deleteOriginalGeometries = false;
@@ -113,7 +136,7 @@
 //    private final Map<String, String> options;
 
     private final FeatureStore featureStore;
-
+    
     public OffsetEditingProvider(ProviderServices providerServices, DynObject parameters) {
         super(providerServices);
         this.featureStore = (FeatureStore) parameters.getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
@@ -146,6 +169,29 @@
                         sideOptions,
                         TYPE.OPTION, TYPE.POSITION).setDataType(DataTypes.STRING);
 
+        DefaultEditingServiceParameterOptions joinStyleOptions = new DefaultEditingServiceParameterOptions()
+                .add(i18nManager.getTranslation(ROUND), ROUND, i18nManager.getTranslation(SHORT_ROUND))
+                .add(i18nManager.getTranslation(MITRE), MITRE, i18nManager.getTranslation(SHORT_MITRE))
+                .add(i18nManager.getTranslation(BEVEL), BEVEL, i18nManager.getTranslation(SHORT_BEVEL));
+
+
+        String joinStyleConsoleMsg = ((EditingProviderServices)providerServices).makeConsoleMessage(
+                i18nManager.getTranslation(JOIN_STYLE), joinStyleOptions);
+
+        this.joinStyleParameter
+                = new DefaultEditingServiceParameter(
+                        "joinStyle",
+                        joinStyleConsoleMsg,
+                        joinStyleOptions,
+                        i18nManager.getTranslation(SHORT_ROUND),
+                        true, 
+                        TYPE.OPTION); //.setDataType(DataTypes.STRING);
+        this.joinStyleParameter.setDefaultValue(ROUND);
+
+
+        this.equidistantOffsets = new DefaultEditingServiceParameter("equidistant_offsets", "equidistant_offsets", true, TYPE.VALUE);
+        this.equidistantOffsets.setDefaultValue(1);
+        
         DefaultEditingServiceParameterOptions deleteOriginalGeometriesOptions2 = new DefaultEditingServiceParameterOptions()
                 .add("delete_original_geometries", true, i18nManager.getTranslation("_yes"))
                 .add("keep_original_geometries", false, i18nManager.getTranslation("_no"));
@@ -159,7 +205,7 @@
                         i18nManager.getTranslation("delete_original_geometries"),
                         consoleMsg,
                         deleteOriginalGeometriesOptions2,
-                        i18nManager.getTranslation("_no"),
+                        false,
                         TYPE.OPTION).setDataType(DataTypes.BOOLEAN);
 
     }
@@ -169,9 +215,11 @@
 
         if (values.get(selectionParameter) == null) {
             return selectionParameter;
-        } else if (values.get(offsetParameter) == null) {
+        }
+        if (values.get(offsetParameter) == null) {
             return offsetParameter;
-        } else if (values.get(sideParameter) == null) {
+        }
+        if (values.get(sideParameter) == null) {
             Object offsetValue = values.get(offsetParameter);
             if (!(offsetValue instanceof Point)) {
                 Double distance = (Double) offsetValue;
@@ -193,80 +241,120 @@
         DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
         EditingProviderManager editingProviderManager
                 = EditingProviderLocator.getProviderManager();
-//        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
+        EditingProviderServices editingProviderServices =
+            (EditingProviderServices) getProviderServices();
+        int subtype;
+        try {
+            subtype = editingProviderServices.getSubType(featureStore);
+        } catch (DataException e2) {
+            throw new DrawServiceException(e2);
+        }
+        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
         ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
         ISymbol auxiliaryLineSymbolEditingDirection = editingProviderManager.getSymbol("auxiliary-line-symbol-editing-direction");
         ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
         ISymbol polygonSymbolEditing = editingProviderManager.getSymbol("polygon-symbol-editing");
 
-        FeatureSelection selected
-                = (FeatureSelection) values.get(selectionParameter);
-        try {
-            if ((selected != null) && !selected.isEmpty()) {
-                Point point; // = null;
-                double distance = 0.0;
-                double side = 1.0;
-                Object offsetValue = values.get(offsetParameter);
+        if (values != null) {
+            Number equidistantOffsetsNumberValue = ((Number) values.get(this.equidistantOffsets));
+            int equidistantOffsetsValue = equidistantOffsetsNumberValue != null ? equidistantOffsetsNumberValue.intValue() : ((Number) this.equidistantOffsets.getDefaultValue()).intValue();
 
-                if (offsetValue != null) {
-                    if (offsetValue instanceof Point) {
-                        distance = Math.abs(getMinDistance(selected, (Point) offsetValue));
+            FeatureSelection selected
+                    = (FeatureSelection) values.get(selectionParameter);
+            try {
+                if ((selected != null) && !selected.isEmpty()) {
+                    Point point; // = null;
+                    double distance = 0.0;
+                    double side = 1.0;
+                    Object offsetValue = values.get(offsetParameter);
+
+                    if (offsetValue != null) {
+                        if (offsetValue instanceof Point) {
+                            distance = Math.abs(getMinDistance(selected, (Point) offsetValue));
+                        } else {
+                            distance = (Double) offsetValue;
+                        }
+
+                        Object sideValue = values.get(sideParameter);
+                        if (sideValue == null) {
+                            point = mousePosition;
+                            side = Math.signum(getMinDistance(selected, point));
+                        } else {
+                            Double signum = getSideSignum((String) sideValue);
+                            if (signum != null) {
+                                side = signum;
+                            }
+                        }
                     } else {
-                        distance = (Double) offsetValue;
-                    }
+                        point = mousePosition;
+                        Geometry closestGeometry = getClosestGeometry(selected, point);
+                        Point closestPoint = getClosestPoint(closestGeometry, point);
+                        distance = getMinDistance(selected, point); //closestPoint.distance(point); //getMinDistance(selected, point);
+                        ISymbol symbol = lineSymbolEditing;
+                        Line auxLine = GeometryUtils.createLine(closestPoint, point, subtype);
+                        drawingStatus.addStatus(
+                                auxLine,
+                                auxiliaryLineSymbolEditing,
+                                ""
+                        );
 
-                    Object sideValue = values.get(sideParameter);
-                    if (sideValue == null) {
-                        point = mousePosition;
-                        side = Math.signum(getMinDistance(selected, point));
-                    } else {
-                        Double signum = getSideSignum((String) sideValue);
-                        if (signum != null) {
-                            side = signum;
-                        }
+                        Point pointText = GeometryUtils.createPoint(
+                                0.5 * (closestPoint.getX() + point.getX()),
+                                0.5 * (closestPoint.getY() + point.getY())
+                        );
+
+                        ISimpleTextSymbol textSymbol = getTextSymbol();
+                        drawingStatus.addStatus(
+                                pointText,
+                                textSymbol,
+                                new DecimalFormat("#.0#").format(distance)
+                        );
+
                     }
-                } else {
-                    point = mousePosition;
-                    distance = getMinDistance(selected, point);
-                }
 
-                DisposableIterator it;
-                it = selected.fastIterator();
+                    int joinStyleValue = coerceJoinStyle(values.get(joinStyleParameter));
 
-                while (it.hasNext()) {
-                    Feature feat = (Feature) it.next();
-                    
-                    ISymbol previewSymbol = this.getPreviewSymbol(feat);
-                    
-                    Geometry transformedGeometry = feat.getDefaultGeometry().offset(distance * side);
+                    DisposableIterator it;
+                    it = selected.fastIterator();
 
-                    ISymbol symbol = null;
-                    if (transformedGeometry instanceof Curve || transformedGeometry instanceof MultiCurve) {
-                        symbol = lineSymbolEditing;
-                        drawingStatus.addStatus(feat.getDefaultGeometry(), auxiliaryLineSymbolEditingDirection, "Direction");
-                    } else if (transformedGeometry instanceof Surface || transformedGeometry instanceof MultiSurface) {
-                        symbol = polygonSymbolEditing;
-                    } else if (transformedGeometry instanceof Point || transformedGeometry instanceof MultiPoint) {
-                        symbol = auxiliaryPointSymbolEditing;
-                    }
-                    if (transformedGeometry instanceof Aggregate) {
-                        int primitivesNumber = ((Aggregate) transformedGeometry).getPrimitivesNumber();
-                        for (int i = 0; i < primitivesNumber; i++) {
-                            final Primitive primitive = ((Aggregate) transformedGeometry).getPrimitiveAt(i);
-                            drawingStatus.addStatus(primitive, symbol, "");
-                            drawingStatus.addStatus(primitive, previewSymbol, "");
+                    while (it.hasNext()) {
+                        Feature feat = (Feature) it.next();
+
+                        ISymbol previewSymbol = this.getPreviewSymbol(feat);
+
+                        for (int c = 1; c <= equidistantOffsetsValue; c++) {
+
+                            Geometry transformedGeometry = feat.getDefaultGeometry().offset(joinStyleValue, c * distance * side);
+
+                            ISymbol symbol = null;
+                            if (transformedGeometry instanceof Curve || transformedGeometry instanceof MultiCurve) {
+                                symbol = lineSymbolEditing;
+                                drawingStatus.addStatus(feat.getDefaultGeometry(), auxiliaryLineSymbolEditingDirection, "Direction");
+                            } else if (transformedGeometry instanceof Surface || transformedGeometry instanceof MultiSurface) {
+                                symbol = polygonSymbolEditing;
+                            } else if (transformedGeometry instanceof Point || transformedGeometry instanceof MultiPoint) {
+                                symbol = auxiliaryPointSymbolEditing;
+                            }
+                            if (transformedGeometry instanceof Aggregate) {
+                                int primitivesNumber = ((Aggregate) transformedGeometry).getPrimitivesNumber();
+                                for (int i = 0; i < primitivesNumber; i++) {
+                                    final Primitive primitive = ((Aggregate) transformedGeometry).getPrimitiveAt(i);
+                                    drawingStatus.addStatus(primitive, symbol, "");
+                                    drawingStatus.addStatus(primitive, previewSymbol, "");
+                                }
+                            } else {
+                                drawingStatus.addStatus(transformedGeometry, symbol, "");
+                                drawingStatus.addStatus(transformedGeometry, previewSymbol, "");
+                            }
                         }
-                    } else {
-                        drawingStatus.addStatus(transformedGeometry, symbol, "");
-                        drawingStatus.addStatus(transformedGeometry, previewSymbol, "");
                     }
+                    DisposeUtils.disposeQuietly(it);
                 }
-                DisposeUtils.disposeQuietly(it);
+            } catch (Exception e) {
+                throw new DrawServiceException(e);
             }
-            return drawingStatus;
-        } catch (Exception e) {
-            throw new DrawServiceException(e);
         }
+        return drawingStatus;
     }
 
     /**
@@ -279,6 +367,11 @@
      * @throws GeometryException
      */
     private double getMinDistance(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
+//        Geometry closestGeometry = getClosestGeometry(selected, point);
+//        if(closestGeometry != null){
+//            return closestGeometry.distance(point);
+//        }
+//        //No debería pasar por aquí
         double minorDistance = Double.POSITIVE_INFINITY;
         DisposableIterator it;
         it = selected.fastIterator();
@@ -294,7 +387,26 @@
         return minorDistance;
 
     }
+    
+    private Geometry getClosestGeometry(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
+        double minorDistance = Double.POSITIVE_INFINITY;
+        DisposableIterator it;
+        it = selected.fastIterator();
+        Geometry closestGeometry = null;
+        while (it.hasNext()) {
+            Feature feat = (Feature) it.next();
+            Geometry geometry = feat.getDefaultGeometry();
+            double distance = getDistance(geometry, point);
+            if (distance < minorDistance) {
+                closestGeometry = geometry;
+                minorDistance = distance;
+            }
+        }
+        it.dispose();
+        return closestGeometry;
 
+    }
+
     /**
      * @param geometry
      * @param point
@@ -304,6 +416,11 @@
      * @throws GeometryException
      */
     private double getDistance(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
+//        Point closest = getClosestPoint(geometry, point);
+//        if(closest != null) {
+//            return closest.distance(point);
+//        }
+        //No debería pasar por aquí
         GeometryManager geomManager = GeometryLocator.getGeometryManager();
         if (geometry instanceof Arc) {
             Arc arc = (Arc) geometry;
@@ -434,53 +551,116 @@
         return 0.0;
     }
 
+    
+    private Point getClosestPoint(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
+        GeometryManager geomManager = GeometryLocator.getGeometryManager();
+        if (geometry instanceof Line) {
+            Line line = (Line) geometry;
+            return (Point)line.closestPoints(point)[0];
+        } else {
+            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+        }
+//        if (geometry instanceof Arc) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//
+//        if (geometry instanceof Circle) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//        if (geometry instanceof Circumference) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//        if (geometry instanceof PeriEllipse) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//        if (geometry instanceof Ellipse) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//
+//        if (geometry instanceof Spline || geometry instanceof FilledSpline) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//
+//
+//        if (geometry instanceof Polygon) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//
+//        if (geometry instanceof Aggregate) {
+//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
+//        }
+//        return null;
+    }
+
+//    
     @Override
     public void stop() {
         values.clear();
     }
 
+    @Override
+    public void restart() throws StartServiceException, InvalidEntryException, StopServiceException {
+//        values.put(selectionParameter, null);
+        values.put(offsetParameter, null);
+        values.put(sideParameter, null);
+        values.put(deleteOriginalGeometriesParameter, null);
+    }
+
+    
     private void validateAndInsertValue(EditingServiceParameter param,
             Object value) throws InvalidEntryException {
         I18nManager i18nManager = ToolsLocator.getI18nManager();
 
-        if (param == selectionParameter) {
-            if (value instanceof FeatureSelection) {
-                values.put(param, value);
-            }
-        } else if (param == offsetParameter) {
-            if (value instanceof Point) {
-                try {
+        try {
+            if (param == selectionParameter) {
+                if (value instanceof FeatureSelection) {
+                    values.put(param, value);
+                }
+            } else if (param == joinStyleParameter) {
+                if (value instanceof String) {
+                    values.put(param, fixJoinStyle(value));
+                }
+            } else if (param == offsetParameter) {
+                if (value instanceof Point) {
                     Double distance = getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value);
+                    if (distance == 0.0) {
+                        throw new IllegalArgumentException("distance can't be 0");
+                    }
                     values.put(param, Math.abs(distance));
                     values.put(sideParameter, coerceSide(distance));
-                } catch (Exception e) {
-                    throw new InvalidEntryException(e);
+                    return;
                 }
-                return;
-            }
-            if (value instanceof Double) {
-                Double distance = (Double) value;
-                if (distance >= 0) {
-                    values.put(param, value);
-                } else {
-                    values.put(param, Math.abs(distance));
-                    values.put(sideParameter, coerceSide(distance));
+                if (value instanceof Double) {
+                    Double distance = (Double) value;
+                    if (distance > 0) {
+                        values.put(param, value);
+                    } else if (distance == 0.0) {
+                        throw new IllegalArgumentException("distance can't be 0");
+                    } else {
+                        values.put(param, Math.abs(distance));
+                        values.put(sideParameter, coerceSide(distance));
+                    }
                 }
-            }
-        } else if (param == sideParameter) {
-            if (value instanceof Point) {
-                try {
+            } else if (param == sideParameter) {
+                if (value instanceof Point) {
                     values.put(param, coerceSide(getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value)));
-                } catch (Exception e) {
-                    throw new InvalidEntryException(e);
+                    return;
                 }
-                return;
+                if (value instanceof String) {
+                    values.put(param, coerceSide(value));
+                }
+            } else if (param == equidistantOffsets) {
+                if (value instanceof Number) {
+                    int intValue = ((Number) value).intValue();
+                    if(intValue >= 1) {
+                        values.put(param, ((Number) value).intValue());
+                    }
+                }
+            } else if (param == deleteOriginalGeometriesParameter) {
+                values.put(param, param.getOptions2().getValue(value, param.getDefaultValue()));
             }
-            if (value instanceof String) {
-                values.put(param, coerceSide(value));
-            }
-        } else if (param == deleteOriginalGeometriesParameter) {
-            values.put(param, param.getOptions2().getValue(value, param.getDefaultValue()));
+        } catch (Exception e) {
+            throw new InvalidEntryException(e);
         }
 
     }
@@ -499,6 +679,25 @@
         throw new InvalidEntryException(null);
     }
 
+    private String fixJoinStyle(Object value) throws InvalidEntryException {
+
+        if (value instanceof String) {
+            I18nManager i18nManager = ToolsLocator.getI18nManager();
+            String joinStyleTrim = ((String)value).trim();
+            if (StringUtils.equalsIgnoreCase(joinStyleTrim, ROUND)
+                    || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(ROUND), joinStyleTrim)) {
+                return ROUND;
+            } else if (StringUtils.equalsIgnoreCase(joinStyleTrim, BEVEL)
+                    || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(BEVEL), joinStyleTrim)) {
+                return BEVEL;
+            } else if (StringUtils.equalsIgnoreCase(joinStyleTrim, MITRE)
+                    || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(MITRE), joinStyleTrim)) {
+                return MITRE;
+            }
+        }
+        throw new InvalidEntryException(null);
+    }
+
     private Double getSideSignum(String side) {
         I18nManager i18nManager = ToolsLocator.getI18nManager();
         String sideTrim = side.trim();
@@ -517,8 +716,10 @@
         List<EditingServiceParameter> list
                 = new ArrayList<>();
         list.add(selectionParameter);
+        list.add(joinStyleParameter);
         list.add(offsetParameter);
         list.add(sideParameter);
+        list.add(equidistantOffsets);
         list.add(deleteOriginalGeometriesParameter);
         return list;
     }
@@ -552,44 +753,48 @@
                 double distance = ((Double) values.get(offsetParameter)) * side;
                 DisposableIterator it;
                 it = selected.fastIterator();
+                int joinStyleValue = coerceJoinStyle(values.get(joinStyleParameter));
+                Number equidistantOffsetsNumberValue = ((Number) values.get(this.equidistantOffsets));
+                int equidistantOffsetsValue = equidistantOffsetsNumberValue != null ? equidistantOffsetsNumberValue.intValue() : ((Number)this.equidistantOffsets.getDefaultValue()).intValue();
 
                 while (it.hasNext()) {
                     Feature feature = (Feature) it.next();
-                    Geometry geom;
-                    try {
-                        geom = feature.getDefaultGeometry().offset(distance);
-                    } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
-                        throw new FinishServiceException(e);
-                    }
+                    for (int c = 1; c <= equidistantOffsetsValue; c++) {
 
-//                    if (this.deleteOriginalGeometries) {
-                    if ((boolean)values.get(deleteOriginalGeometriesParameter)) { //this.deleteOriginalGeometries) {
-                        // Se sustituye la geometría original por la
-                        // calculada
-                        EditableFeature editableFeature
-                                = feature.getEditable();
-                        editableFeature.setDefaultGeometry(geom);
-                        ((EditingProviderServices) getProviderServices())
-                                .updateFeatureInFeatureStore(editableFeature,
-                                        featureStore);
-                    } else {
-                        // Se crea una feature nueva copiando los valores de
-                        // la feature original excepto aquellos que sean PK
-                        EditingProviderServices editingProviderServices
-                                = (EditingProviderServices) getProviderServices();
-                        EditableFeature editableFeature
-                                = editingProviderServices
-                                        .getFeatureCopyWithoutUniqueIndex(featureStore,
-                                                feature);
-                        editableFeature.setDefaultGeometry(geom);
-                        editingProviderServices
-                                .insertFeatureIntoFeatureStore(editableFeature,
-                                        featureStore);
+                        Geometry geom;
+                        try {
+                            geom = feature.getDefaultGeometry().offset(joinStyleValue, c * distance);
+                        } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
+                            throw new FinishServiceException(e);
+                        }
+
+                        if ((boolean) values.get(deleteOriginalGeometriesParameter) && c == 1) {
+                            // Se sustituye la geometría original por la primera calculada
+                            EditableFeature editableFeature
+                                    = feature.getEditable();
+                            editableFeature.setDefaultGeometry(geom);
+                            ((EditingProviderServices) getProviderServices())
+                                    .updateFeatureInFeatureStore(editableFeature,
+                                            featureStore);
+                        } else {
+                            // Se crea una feature nueva copiando los valores de
+                            // la feature original excepto aquellos que sean PK
+                            EditingProviderServices editingProviderServices
+                                    = (EditingProviderServices) getProviderServices();
+                            EditableFeature editableFeature
+                                    = editingProviderServices
+                                            .getFeatureCopyWithoutUniqueIndex(featureStore,
+                                                    feature);
+                            editableFeature.setDefaultGeometry(geom);
+                            editingProviderServices
+                                    .insertFeatureIntoFeatureStore(editableFeature,
+                                            featureStore);
+                        }
                     }
 
                 }
                 it.dispose();
-                featureStore.getFeatureSelection().deselectAll();
+//                featureStore.getFeatureSelection().deselectAll();
             }
         } catch (DataException e) {
             throw new FinishServiceException(e);
@@ -638,9 +843,49 @@
             }
         }
     }
-
+    
     @Override
     public String getName() {
         return OffsetEditingProviderFactory.PROVIDER_NAME;
     }
+
+    private int coerceJoinStyle(Object joinStyle) {
+        if(joinStyle instanceof String) {
+            switch ((String)joinStyle) {
+                default:
+                case ROUND:
+                    return JOIN_STYLE_ROUND;
+                case MITRE:
+                    return Geometry.JOIN_STYLE_MITRE;
+                case BEVEL:
+                    return Geometry.JOIN_STYLE_BEVEL;
+            }
+        }
+        return JOIN_STYLE_ROUND;
+    }
+
+    @Override
+    public boolean isEnabled(EditingServiceParameter parameter) {
+        if (parameter == joinStyleParameter) {
+            return true;
+        }
+        if (parameter == equidistantOffsets) {
+            return true;
+        }
+        return true;
+    }
+    
+    private ISimpleTextSymbol getTextSymbol(){
+        SymbologyManager symbologyManager = SymbologyLocator.getSymbologyManager();
+        ISimpleTextSymbol textSymbol = symbologyManager.createSimpleTextSymbol();
+        textSymbol.setFontSize(10);
+        return textSymbol;
+    }
+    
+    @Override
+    public Object getValue(EditingServiceParameter parameter) {
+        return values!=null?values.get(parameter):null;
+    }
+
+    
 }
