QCad源码分析 第四章

分析一下线实体的添加操作,两点划线,下面是Line2P.js中的部分代码:

function Line2P(guiAction) {
    Line.call(this, guiAction);

	//点的列表
    // list of points drawn:
    this.pointList = [];
    // index of point that was drawn last, used for tool undo / redo:
	//保存点的列表,用于撤销和重做
    this.pointListIndex = -1;
    // list of entities drawn:
	//绘制的实体列表
    this.entityIdList = [];

	//点
    this.point1 = undefined;
    this.point2 = undefined;

    this.setUiOptions(["../Line.ui", "Line2P.ui"]);
}

//设置Line2P的原型为Line
Line2P.prototype = new Line();

//状态
Line2P.State = {
    SettingFirstPoint : 0,
    SettingNextPoint : 1
};

//当action激活时自动调用
Line2P.prototype.beginEvent = function() {
    Line.prototype.beginEvent.call(this);

    this.setState(Line2P.State.SettingFirstPoint);
    this.updateButtonStates();
};

//设置状态
Line2P.prototype.setState = function(state) {
    Line.prototype.setState.call(this, state);

	//文档接口会根据这个模式选择调用相应的交互事件【例如是调用pickCoordinate还是调用鼠标的其他事件】
    this.getDocumentInterface().setClickMode(RAction.PickCoordinate);
	//设置鼠标样式
    this.setCrosshairCursor();

    var appWin = RMainWindowQt.getMainWindow();
    switch (this.state) {
		//如果是第一次点击鼠标
    case Line2P.State.SettingFirstPoint:
        var trFirstPoint = qsTr("First point");
		//设置命令行中的提示信息
        this.setCommandPrompt(trFirstPoint);
        this.setLeftMouseTip(trFirstPoint);
        this.setRightMouseTip(EAction.trCancel);
        this.pointList = [];
        this.pointListIndex = -1;
        this.entityIdList = [];
        break;

    case Line2P.State.SettingNextPoint:
		//如果是第二次点击鼠标
        var trNextPoint = qsTr("Next point");
        this.setCommandPrompt(trNextPoint);
        this.setLeftMouseTip(trNextPoint);
        this.setRightMouseTip(qsTr("Done"));
        break;
    }

    EAction.showSnapTools();
};

//拾取坐标
Line2P.prototype.pickCoordinate = function(event, preview) {
    var di = this.getDocumentInterface();

    switch (this.state) {
		//如果状态是第一个点,
    case Line2P.State.SettingFirstPoint:
        if (!preview) {
            this.point1 = event.getModelPosition();
			//添加第一个点
            this.pointList.splice(0, 0, this.point1);
			//设置索引
            this.pointListIndex = 0;
			//应该是将第一点设置为相对位置,使用矩阵???
            di.setRelativeZero(this.point1);
			//将状态改为第二个点
            this.setState(Line2P.State.SettingNextPoint);
        }
        break;

    case Line2P.State.SettingNextPoint:
        this.point2 = event.getModelPosition();
        if (preview) {
            this.updatePreview();
        }
        else {
			//获取一个操作
            var op = this.getOperation(preview);
            if (!isNull(op)) {
                if (!this.isRayOrXLine()) {
					//如果不是射线或者X线就++
                    this.pointListIndex++;
                }
				//获取文档
                var doc = this.getDocument();
				//添加到文档接口当中【两个点构成一个实体】
                var trans = di.applyOperation(op);
                var id = this.getLineEntityId(trans);

                if (!this.isRayOrXLine()) {
					//添加到相应的位置
                    this.pointList.splice(this.pointListIndex, 0, this.point2);
					//将实体存储起来
                    this.entityIdList.splice(this.pointListIndex-1, 0, id);
					//将相对位置重置为第二个点
                    di.setRelativeZero(this.point2);
					//第二个点作为第一个点,然后创建另一个线实体
                    this.point1 = this.point2;
                }

//                qDebug("this.pointList: ", this.pointList);
//                qDebug("this.entityIdList: ", this.entityIdList);
//                qDebug("this.pointListIndex: ", this.pointListIndex);
            }
        }
        break;
    }

    if (!preview) {
        this.updateButtonStates();
    }
};

Line2P.prototype.getOperation = function(preview) {
    if (!isVector(this.point1) || !isVector(this.point2)) {
        return undefined;
    }

	//创建线实体
    var e = this.createLineEntity(this.getDocument(), this.point1, this.point2);
	//将实体封装到操作当中
    return new RAddObjectOperation(e, this.getToolTitle());
};

当一个Action被触发后会调用Action的beginEvent事件,Line2P重写了RAction的beginEvent方法,在这个函数中调用

this.setState(Line2P.State.SettingFirstPoint);

这个函数设置了一个自定义的标志Line2P.State.SettingFirstPoint,代表这是第一个按下的点。在setState()函数中

//文档接口会根据这个模式选择调用相应的交互事件【例如是调用pickCoordinate还是调用鼠标的其他事件】
    this.getDocumentInterface().setClickMode(RAction.PickCoordinate);

设置了点击模式后,下次鼠标点击后会在documentinterface中判断模式,根据这个模式调用Line2P类的函数

//拾取坐标
Line2P.prototype.pickCoordinate = function(event, preview)

在上面的函数中会调用下面的代码

//获取一个操作
            var op = this.getOperation(preview);
            if (!isNull(op)) {
                if (!this.isRayOrXLine()) {
					//如果不是射线或者X线就++
                    this.pointListIndex++;
                }
				//获取文档
                var doc = this.getDocument();
				//添加到文档接口当中【两个点构成一个实体】
                var trans = di.applyOperation(op);
                var id = this.getLineEntityId(trans);

                if (!this.isRayOrXLine()) {
					//添加到相应的位置
                    this.pointList.splice(this.pointListIndex, 0, this.point2);
					//将实体存储起来
                    this.entityIdList.splice(this.pointListIndex-1, 0, id);
					//将相对位置重置为第二个点
                    di.setRelativeZero(this.point2);
					//第二个点作为第一个点,然后创建另一个线实体
                    this.point1 = this.point2;
                }

//                qDebug("this.pointList: ", this.pointList);
//                qDebug("this.entityIdList: ", this.entityIdList);
//                qDebug("this.pointListIndex: ", this.pointListIndex);
            }

这个函数中的过程伪代码如下:

documentinterface.applyOperation(new AddOperation(new LineEntity(new LineEntityData())));

在documentinterface中

RTransaction RDocumentInterface::applyOperation(ROperation* operation) {
	//如果当前的操作是null就返回
    if (operation==NULL) {
        qWarning() << "RDocumentInterface::applyOperation: operation is NULL";
        return RTransaction();
    }

	//??
    if (document.getAutoTransactionGroup()) {
        operation->setTransactionGroup(document.getTransactionGroup());
    }

	//将具体的数据库操作放到ROperation完成【功能独立】
    RTransaction transaction = operation->apply(document, false);
    if (transaction.isFailed()) {
        qWarning() << "RDocumentInterface::applyOperation: "
                "transaction failed";
        if (RMainWindow::hasMainWindow()) {
            RMainWindow::getMainWindow()->handleUserWarning("#transaction_failed");
        }
    }

	//获取被影响的id
    QList<RObject::Id> objectIds = transaction.getAffectedObjects();

	//清空之前的视图
    clearPreview();

    objectChangeEvent(objectIds);

    if (RMainWindow::hasMainWindow() && notifyGlobalListeners) {
        RMainWindow::getMainWindow()->postTransactionEvent(transaction,
                    transaction.hasOnlyChanges(), operation->getEntityTypeFilter());
    }

    delete operation;

    notifyTransactionListeners(&transaction);

    return transaction;
}

在documentinterface中将文档放入到operation中完成对文档的操作RTransaction transaction = operation->apply(document, false);

RTransaction RAddObjectsOperation::apply(RDocument& document, bool preview) {
	//将文档封装成一个事务,通过事务处理文档中的实体
    RTransaction transaction(document.getStorage(), text, undoable);
    transaction.setRecordAffectedObjects(recordAffectedObjects);
    transaction.setSpatialIndexDisabled(spatialIndexDisabled);
    transaction.setAllowAll(allowAll);
    transaction.setAllowInvisible(allowInvisible);
    transaction.setGroup(transactionGroup);

    for (int i=0; i<addedObjects.size(); ++i) {
        if (limitPreview && preview && i>RSettings::getPreviewEntities()) {
            break;
        }

        RModifiedObjects modObj = addedObjects[i];

        if (modObj.object.isNull()) {
            transaction.endCycle();
            //qWarning() << "RAddObjectsOperation::apply: "
            //        "list contains NULL object";
            continue;
        }

        if (modObj.getDelete()) {
            transaction.deleteObject(modObj.object);
            continue;
        }

        QSet<RPropertyTypeId> props;
        if (modObj.getGeometryOnly()) {
            // we know that only geometry was modified for this object:
            props = modObj.object->getPropertyTypeIds(RPropertyAttributes::Geometry);
        }

        transaction.addObject(
            modObj.object,
            !modObj.getUseAttributes(),
            modObj.getForceNew(),
            props
        );
    }

    transaction.end();
    return transaction;
}

通过事务将实体添加到文档的RStorage当中。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值