Following discussion from previous thread, here's a method to convert free-drawings to some set of standard shapes, however using a custom class instead of unconnected links:
diagramView.setBehavior(Behavior.Custom);
diagramView.setCustomNodeType(FreeDrawTool.class);
diagram.addDiagramListener(new DiagramAdapter()
{
@Override
public void nodeCreated(NodeEvent e)
{
DiagramNode node = e.getNode();
if (node instanceof FreeDrawTool)
{
FreeDrawTool freeDraw = (FreeDrawTool)node;
ShapeNode replacement = freeDraw.standardShapeReplacement(
new Shape[]
{
Shape.fromId("Rectangle"),
Shape.fromId("Decision")
});
if (replacement != null)
{
diagram.getNodes().remove(freeDraw);
diagram.getNodes().add(replacement);
diagramView.cancelDrag();
}
else
{
// replace with default shape or leave free-drawing?
}
}
}
});
class FreeDrawTool extends DiagramNode
{
ArrayList<PointF> points = new ArrayList<PointF>();
@Override
public void draw(Canvas g, RenderOptions options)
{
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(android.graphics.Color.BLACK);
paint.setStrokeWidth(1);
for (int p = 0; p < points.size() - 1; p++)
{
PointF point1 = points.get(p);
PointF point2 = points.get(p + 1);
g.drawLine(point1.x, point1.y, point2.x, point2.y, paint);
}
}
@Override
protected void drawShadow(Canvas g, RenderOptions options)
{
}
@Override
protected void startCreate(PointF org)
{
super.startCreate(org);
points.add(org);
}
@Override
protected void updateCreate(PointF current)
{
super.updateCreate(current);
points.add(current);
}
@Override
protected boolean allowCreate(PointF current, InteractionState ist)
{
return true;
};
ShapeNode standardShapeReplacement(Shape[] shapes)
{
RectF bounds = calcBounds();
Shape bestShape = null;
double bestDeviation = Double.MAX_VALUE;
final double maxDeviation = 20;
ShapeNode testNode = new ShapeNode();
testNode.setBounds(bounds);
for (Shape shape : shapes)
{
testNode.setShape(shape);
double deviation = 0;
for (PointF point : points)
{
PointF nearest = testNode.getNearestBorderPoint(point);
deviation += Utilities.distance(point, nearest);
}
deviation /= points.size();
if (deviation < bestDeviation)
{
bestShape = shape;
bestDeviation = deviation;
}
}
testNode.setShape(bestShape);
return bestDeviation < maxDeviation ? testNode : null;
}
RectF calcBounds()
{
PointF pt1 = points.get(0);
PointF pt2 = points.get(points.size()-1);
float l = Math.min(pt1.x, pt2.x);
float r = Math.max(pt1.x, pt2.x);
float t = Math.min(pt1.y, pt2.y);
float b = Math.max(pt1.y, pt2.y);
for (int i = 1; i < points.size() - 1; ++i)
{
l = Math.min(l, points.get(i).x);
t = Math.min(t, points.get(i).y);
r = Math.max(r, points.get(i).x);
b = Math.max(b, points.get(i).y);
}
return new RectF(l, t, r, b);
}
}
It looks cute but gets tiresome if you have to draw a lot; I think users will prefer selecting a default shape and drawing with single swipe instead of having to trace shape outlines.
I hope that helps,
Stoyan