Arrow comment
Below we will introduce how to use mxcad plug-in to achieve the function of arrow annotation in CAD drawings, in which the user clicks the canvas to determine the starting point of the arrow, and then continuously clicks the canvas to determine the vertex and end position of the arrow lead. In the arrow guide function, users can customize the arrow shape, as well as the content of superscript text and subscript text, and modify the text position according to the drawing needs. The arrow quote function can help users quickly mark the content of the drawing, and increase the integrity and readability of the drawing content.
Function implementation
- Implement a custom arrow reference class
In order to facilitate later management and annotation modification, We can through inheritance McDbCustomEntity Customize the entity class to extend the implementation of the custom arrow reference class. Then, We can use McDbMText or McDbText measurement information text object, will mark information on the page.
In the following example, we provide arrow, point, cross, half arrow and other arrow styles in the arrow reference class, as well as the alignment of the upper and lower script text on the line end, the line in the middle, the line end, etc. Users can refer to the following example code for secondary development according to their own project needs.
// Custom arrow reference classes
class McDbTestArrowCitation extends McDbCustomEntity {
// Defines a point object inside McDbTestConMeasurement
// Arrow line points group
private points: McGePoint3d[] = [];
// Text point location set
private positionArr: McGePoint3d[] = [];
// Text height
private height: number = 0;
// Superscript text content
private _textUp: string = "";
// Subscript text content
private _textDown: string = "";
// Arrow style
private _arrowType: string = "";
// Alignment mode
private _alginType: string = "";
// Initial record length
private arrowLength: number = 0;
// Text rotation Angle
private angle: number = 0;
// constructor
constructor(imp?: any) {
super(imp);
}
// Create function
public create(imp: any) {
return new McDbTestArrowCitation(imp)
}
// Get class name
public getTypeName(): string {
return "McDbTestArrowCitation";
}
//Sets or gets the text word height
public set textHeight(val: number) {
this.height = val;
}
public get textHeight(): number {
return this.height;
}
//Sets or gets superscript text
public set textUp(val: string) {
this._textUp = val;
}
public get textUp(): string {
return this._textUp;
}
//Sets or gets the subscript text
public set textDown(val: string) {
this._textDown = val;
}
public get textDown(): string {
return this._textDown;
}
//Sets or gets the arrow style
public set arrowType(val: string) {
this._arrowType = val;
}
public get arrowType(): string {
return this._arrowType;
}
//Sets or gets the alignment style
public set alginType(val: string) {
this._alginType = val;
}
public get alginType(): string {
return this._alginType;
}
// Read from defined entity data
public dwgInFields(filter: IMcDbDwgFiler): boolean {
this.points = filter.readPoints("points").val;
this.positionArr = filter.readPoints("positionArr").val;
this._textDown = filter.readString("textDown").val;
this._textUp = filter.readString("textUp").val;
this._arrowType = filter.readString("arrowType").val;
this._alginType = filter.readString("alginType").val;
this.arrowLength = filter.readLong("arrowLength").val;
this.angle = filter.readDouble("angle").val;
this.height = filter.readDouble("height").val;
return true;
}
// Writes custom entity data
public dwgOutFields(filter: IMcDbDwgFiler): boolean {
filter.writePoints("points", this.points);
filter.writePoints("positionArr", this.positionArr);
filter.writeString("textDown", this._textDown);
filter.writeString("textUp", this._textUp);
filter.writeString("arrowType", this._arrowType);
filter.writeString("alginType", this._alginType);
filter.writeLong("arrowLength", this.arrowLength);
filter.writeDouble("angle", this.angle);
filter.writeDouble("height", this.height);
return true;
}
// Moves the pinch point of a custom object
public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
this.assertWrite();
const length = this.points.length
if (iIndex <= length - 1) {
this.points[iIndex].x += dXOffset;
this.points[iIndex].y += dYOffset;
this.points[iIndex].z += dZOffset;
}
if (iIndex === length - 1) {
this.positionArr.forEach(position => {
position.x += dXOffset;
position.y += dYOffset;
position.z += dZOffset;
});
this.reCountData();
};
if (iIndex > length - 1) {
this.positionArr.forEach((position, index) => {
if (iIndex - length === index) {
position.x += dXOffset;
position.y += dYOffset;
position.z += dZOffset;
}
});
}
};
// Gets the pinch point of a custom object
public getGripPoints(): McGePoint3dArray {
let ret = new McGePoint3dArray()
this.points.forEach(pt => {
ret.append(pt)
});
this.positionArr.forEach(pt => {
ret.append(pt);
})
return ret;
};
/**
* Draw arrow style
* A : arrow
* HA : half arrow
* P : point
* C : corss
*/
private drawArrow(): McDbEntity[] {
const pt1 = this.points[0];
const pt2 = this.points[1];
if (this._arrowType === 'A' || this._arrowType === 'HA') {
const vec = pt2.sub(pt1).normalize().mult(this.arrowLength);
const pt = pt1.clone().addvec(vec);
const _vec = vec.clone().rotateBy(Math.PI / 2).normalize().mult(this.arrowLength / 8);
const pt3 = pt.clone().addvec(_vec);
const pt4 = pt.clone().subvec(_vec);
const solid = new McDbHatch();
this._arrowType === 'A' ? solid.appendLoop(new McGePoint3dArray([pt1, pt3, pt4])) : solid.appendLoop(new McGePoint3dArray([pt1, pt3, pt]));
return [solid]
}else if(this._arrowType === 'P'){
const solid = new McDbHatch();
solid.appendCircleLoop(pt1.x,pt1.y,this.arrowLength/3);
return [solid]
}else if(this._arrowType === 'C'){
const point1 = pt1.clone().addvec(McGeVector3d.kXAxis.normalize().mult(this.arrowLength/2));
const point2 = pt1.clone().subvec(McGeVector3d.kXAxis.normalize().mult(this.arrowLength/2));
const point3 = pt1.clone().addvec(McGeVector3d.kYAxis.normalize().mult(this.arrowLength/2));
const point4 = pt1.clone().subvec(McGeVector3d.kYAxis.normalize().mult(this.arrowLength/2));
const line1 = new McDbLine(point1,point2);
const line2 = new McDbLine(point3, point4);
return [line1,line2]
}
}
/**
* Drawing text
* L: online end
* M: In line
* R: line end
*/
private drawText(): McDbEntity[] {
const textArr = [];
const textUp = new McDbText();
textUp.height = this.height;
textUp.textString = this._textUp;
textUp.position = textUp.alignmentPoint = this.positionArr[0];
textUp.horizontalMode = McDb.TextHorzMode.kTextLeft;
textUp.rotate(this.positionArr[0], this.angle);
if (this._alginType === 'M' || this._alginType === 'R') {
const textDown = new McDbMText()
textDown.contents = this._textDown;
textDown.location = this.positionArr[1];
textDown.textHeight = this.height;
textDown.attachment = McDb.AttachmentPoint.kTopCenter;
textDown.rotate(this.positionArr[1], this.angle);
if (this._alginType === 'M') {
textUp.horizontalMode = McDb.TextHorzMode.kTextMid;
}
if (this._alginType === 'R') {
textDown.attachment = McDb.AttachmentPoint.kTopLeft;
}
textArr.push(textDown);
}
textArr.push(textUp);
return textArr
}
// Draw entity
public worldDraw(draw: MxCADWorldDraw): void {
// Draw multiple lines
const pl = new McDbPolyline();
this.points.forEach((pt) => {
pl.addVertexAt(pt);
});
draw.drawEntity(pl);
// Draw an arrow
if(this._arrowType !== 'N' && this.points.length > 1){
const arrowArr = this.drawArrow();
arrowArr.forEach( arrow =>{
draw.drawEntity(arrow)
})
}
if (this.points.length > 1) {
// Draw subscript text
const textArr = this.drawText();
textArr.forEach(text => {
draw.drawEntity(text)
})
}
}
// Recalculate the text position and rotation direction
private reCountData() {
const length = this.points.length;
// Gets the direction and rotation Angle of the last line
if (length > 1) {
const pt1 = this.points[length - 2];
const pt2 = this.points[length - 1];
if (!this.arrowLength) {
this.arrowLength = MxFun.viewCoordLong2Cad(20);
};
if (!this.height) {
this.height = this.arrowLength*(2/3);
};
const vec = pt2.sub(pt1).normalize().mult(this.height / 2);
const _vec = vec.clone().rotateBy(Math.PI / 2).normalize().mult(this.height / 2);
this.angle = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
if (Math.PI * (3 / 2) > this.angle && this.angle > Math.PI / 2) {
this.angle += Math.PI;
_vec.negate();
}
if (this._alginType === 'L') {
// On the online end, only superscript text
const position = pt2.clone().addvec(vec).subvec(_vec);
this.positionArr[0] = position;
} else if (this._alginType === 'M') {
// In the middle of the line, the upper and lower scripts are centered
const distance = pt1.distanceTo(pt2);
const midPt = pt1.clone().addvec(vec.normalize().mult(distance / 2))
this.positionArr[1] = midPt.clone().subvec(_vec);
this.positionArr[0] = midPt.clone().addvec(_vec);
} else if (this._alginType === 'R') {
// Line end, upper and lower script at the end
this.positionArr[1] = pt2.clone().addvec(vec).subvec(_vec);
this.positionArr[0] = pt2.clone().addvec(vec).addvec(_vec);
}
}
}
// Add vertex
public addVertex(pt: McGePoint3d) {
this.assertWrite();
this.points.push(pt);
this.reCountData();
}
// Get vertex array
public getPoints() {
return this.points;
}
}
- Register custom class information
new McDbTestArrowCitation().rxInit();
- Write method, call McDbTestArrowCitation custom arrow reference class to implement arrow reference function
- Set arrow style, upper and lower script text content and alignment
We can use MxCADUiPrString() according to the according to user input by the subscript text content, Or assign values directly by some other means. When you select an arrow style or alignment, We can use MxCADUiPrKeyWord() set up corresponding operation according to user's choice of key words.
// Set arrow style
const getArrowStyle = new MxCADUiPrKeyWord()
getArrowStyle.setMessage("Please select the arrow style:")
getArrowStyle.setKeyWords("[Arrow(A)/Half arrow(HA)/Dot(P)/Cross(C)/None(N)]")
let arrowStyle = await getArrowStyle.go();
// Set alignment
const getAlignType = new MxCADUiPrKeyWord()
getAlignType.setMessage("Please select the text alignment above and below:")
getAlignType.setKeyWords("[Line start(L)/Line center(M)/Line end(R)]")
let alignType = await getAlignType.go();
/**
* Set the subscript text
* Only superscript text can be set on the online end
*/
const getStrUp = new MxCADUiPrString();
getStrUp.setMessage('Please set the superscript text content:');
let strUp = await getStrUp.go();
if (!strUp) strUp = "上";
let strDown = "";
if(alignType === "M" || alignType === "R"){
const getStrDown = new MxCADUiPrString();
getStrDown.setMessage('Please set the subscript text content:');
strDown = await getStrDown.go();
if (!strDown) strDown = "下";
}
- Get the starting point of the arrow and the vertex of the lead
We can use take object MxCADUiPrPoint continuous take to get the arrow and lead the starting point of each vertex. According to the information obtained in the above steps, a new arrow reference object is constructed and dynamically drawn for user observation.
const arrowCiatat = new McDbTestArrowCitation();
arrowCiatat.textUp = strUp;
arrowCiatat.textDown = strDown;
arrowCiatat.arrowType = arrowStyle;
arrowCiatat.alginType = alginType;
const getPoint = new MxCADUiPrPoint();
getPoint.setMessage('Specify arrow start:');
const point = await getPoint.go();
if (!point) return;
arrowCiatat.addVertex(point);
while (true) {
const getPt = new MxCADUiPrPoint();
getPt.setMessage('Specify the next point or end point and right-click to finish');
getPt.setUserDraw((pt, pw) => {
const _clone = arrowCiatat.clone() as McDbTestArrowCitation;
_clone.addVertex(pt);
pw.drawMcDbEntity(_clone)
})
const pt = await getPt.go();
if (!pt) break;
arrowCiatat.addVertex(pt);
}
const mxcad = MxCpp.getCurrentMxCAD();
mxcad.drawEntity(arrowCiatat);
Functional practice
Practical effects are as follows:
- Click the arrow quote button to execute the arrow quote method
- Follow the command line prompts to set the arrow style, subscript text content, and alignment of the arrow annotations
- enter an option or content in the input box and click Enter to confirm
- Click on the drawing to determine the starting point of the arrow and move the mouse to determine the vertex of the lead
- Click the right mouse button to end the point, successfully draw the arrow guide
- After the drawing is completed, the left mouse button can click the arrow guide object to adjust the position of the object through the pinch point