Код AS3:
package {
import flash.display.GraphicsPathCommand;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
public class Main extends Sprite {
private static const RUBBER_SIZE:Number = 50;
private var _rubber:Shape;
private var _button:TextField;
public function Main():void {
_button = new TextField();
_button.autoSize = TextFieldAutoSize.LEFT;
_button.selectable = false;
_button.border = true;
_button.text = "Erase on/off";
_button.addEventListener(MouseEvent.MOUSE_DOWN, onButtonMouseDown);
addChild(_button);
_rubber = new Shape();
_rubber.graphics.lineStyle(0, 0x000000);
_rubber.graphics.beginFill(0xffffff);
_rubber.graphics.drawRect(0, 0, RUBBER_SIZE, RUBBER_SIZE);
_rubber.graphics.endFill();
_rubber.visible = false;
addChild(_rubber);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseMove(event:MouseEvent):void {
_rubber.x = mouseX - RUBBER_SIZE * .5;
_rubber.y = mouseY - RUBBER_SIZE * .5;
}
private function onMouseDown(event:MouseEvent):void {
if (_rubber.visible) {
GeomUtil.eraseSquare(_data, _commands, _rubber.x, _rubber.y, RUBBER_SIZE);
} else {
_data.push(mouseX);
_data.push(mouseY);
_commands.push(_commands.length == 0 ? GraphicsPathCommand.MOVE_TO : GraphicsPathCommand.LINE_TO);
}
redraw();
}
private var _commands:Vector.<int> = new Vector.<int>();
private var _data:Vector.<Number> = new Vector.<Number>();
private function redraw():void {
graphics.clear();
graphics.lineStyle(0, 0x000000);
graphics.drawPath(_commands, _data);
}
private function onButtonMouseDown(event:MouseEvent):void {
event.stopPropagation();
_rubber.visible = !_rubber.visible;
}
}
}
import flash.display.GraphicsPathCommand;
import flash.geom.Rectangle;
class GeomUtil {
private static var _rx0:Number;
private static var _ry0:Number;
private static var _rx1:Number;
private static var _ry1:Number;
public static function eraseSquare(data:Vector.<Number>, commands:Vector.<int>, rubberX:Number, rubberY:Number, size:Number):void {
_rx0 = rubberX;
_ry0 = rubberY;
_rx1 = _rx0 + size;
_ry1 = _ry0 + size;
var i:int;
var c:Number;
// Мы тут будем кое-чего удалять в векторе во время прохода, но если пойдем справа, то поломаться не должно
for (i = commands.length; i-- > 1; ) {
if (commands[i] == GraphicsPathCommand.LINE_TO) {
var x0:Number = data[(i - 1) << 1];
var y0:Number = data[((i - 1) << 1) + 1];
var x1:Number = data[i << 1];
var y1:Number = data[(i << 1) + 1];
var boundsIntersects:Boolean =
(x1 > x0 ? _rx1 > x0 && _rx0 < x1 : _rx1 > x1 && _rx0 < x0) &&
(y1 > y0 ? _ry1 > y0 && _ry0 < y1 : _ry1 > y1 && _ry0 < y0);
if (boundsIntersects) {
var dx:Number = x1 - x0;
var dy:Number = y1 - y0;
var kx0:Number = (_rx0 - x0) / dx;
var ky0:Number = (_ry0 - y0) / dy;
var kx1:Number = (_rx1 - x0) / dx;
var ky1:Number = (_ry1 - y0) / dy;
var k:Number;
var kI:Number;
var ks:Vector.<Number>;
if (InRubber(x0, y0) && InRubber(x1, y1)) {
commands[i] = GraphicsPathCommand.MOVE_TO;
} else if (InRubber(x0, y0)) {
k = 1;
for each (kI in [kx0, ky0, kx1, ky1]) {
if (kI > 0 && kI < k) {
k = kI;
}
}
commands.splice(i, 0, GraphicsPathCommand.MOVE_TO);
data.splice(i << 1, 0, x0 + dx * k, y0 + dy * k);
} else if (InRubber(x1, y1)) {
k = 0;
for each (kI in [kx0, ky0, kx1, ky1]) {
if (kI > k && kI < 1) {
k = kI;
}
}
commands[i] = GraphicsPathCommand.MOVE_TO;
commands.splice(i, 0, GraphicsPathCommand.LINE_TO);
data.splice(i << 1, 0, x0 + dx * k, y0 + dy * k);
} else {
ks = new Vector.<Number>();
if (kx0 >= 0 && kx0 <= 1 && (y0 + kx0 * dy) >= _ry0 && (y0 + kx0 * dy) <= _ry1) {
ks.push(kx0);
}
if (ky0 >= 0 && ky0 <= 1 && (x0 + ky0 * dx) >= _rx0 && (x0 + ky0 * dx) <= _rx1) {
ks.push(ky0);
}
if (kx1 >= 0 && kx1 <= 1 && (y0 + kx1 * dy) >= _ry0 && (y0 + kx1 * dy) <= _ry1) {
ks.push(kx1);
}
if (ky1 >= 0 && ky1 <= 1 && (x0 + ky1 * dx) >= _rx0 && (x0 + ky1 * dx) <= _rx1) {
ks.push(ky1);
}
if (ks.length >= 2) {
if (ks[0] > ks[1]) {
c = ks[0];
ks[0] = ks[1];
ks[1] = c;
}
commands.splice(i, 0, GraphicsPathCommand.LINE_TO, GraphicsPathCommand.MOVE_TO);
data.splice(i << 1, 0, x0 + dx * ks[0], y0 + dy * ks[0], x0 + dx * ks[1], y0 + dy * ks[1]);
}
}
}
}
}
}
private static function InRubber(x:Number, y:Number):Boolean {
return x >= _rx0 && x <= _rx1 && y >= _ry0 && y <= _ry1;
}
}
Здесь тупо обработка случаев пересечения прямых. Что здесь сложного - так это найти способ максимально компактно и аккуратно это сделать (я очень сомневаюсь, код выше реализует это лучшим способом, но кое-как работает)