347 lines
11 KiB
TypeScript
347 lines
11 KiB
TypeScript
import DxfArrayScanner, {IGroup} from '../DxfArrayScanner';
|
||
import * as helpers from '../ParseHelpers'
|
||
import IGeometry, {IEntity, IPoint} from './geomtry';
|
||
|
||
export interface IHatchEntity extends IEntity {
|
||
boundaryLoops: any[];
|
||
definitionLines: any[];
|
||
seedPoints: any[];
|
||
patternName: string;
|
||
isSolid: boolean;
|
||
hatchStyle: string;
|
||
patternType: number;
|
||
patternAngle: number;
|
||
patternScale: number;
|
||
}
|
||
|
||
export default class Hatch implements IGeometry {
|
||
public ForEntityName = 'HATCH' as const;
|
||
|
||
public parseEntity(scanner: DxfArrayScanner, curr: IGroup) {
|
||
let entity = {type: curr.value} as IHatchEntity;
|
||
|
||
let numBoundaryLoops = 0;
|
||
let numDefinitionLines = 0;
|
||
let numSeedPoints = 0;
|
||
|
||
curr = scanner.next();
|
||
while (!scanner.isEOF()) {
|
||
if (curr.code === 0) break;
|
||
|
||
while (numBoundaryLoops > 0) {
|
||
const loop = ParseBoundaryLoop(curr, scanner)
|
||
if (loop) {
|
||
entity.boundaryLoops.push(loop);
|
||
numBoundaryLoops--;
|
||
curr = scanner.next();
|
||
} else {
|
||
numBoundaryLoops = 0
|
||
}
|
||
}
|
||
|
||
while (numDefinitionLines > 0) {
|
||
const line = ParseDefinitionLine(curr, scanner)
|
||
if (line) {
|
||
entity.definitionLines.push(line);
|
||
numDefinitionLines--;
|
||
curr = scanner.next();
|
||
} else {
|
||
numDefinitionLines = 0
|
||
}
|
||
}
|
||
|
||
while (numSeedPoints > 0) {
|
||
const pt = ParseSeedPoint(curr, scanner);
|
||
if (pt) {
|
||
entity.seedPoints.push(pt);
|
||
numSeedPoints--;
|
||
curr = scanner.next();
|
||
} else {
|
||
numSeedPoints = 0
|
||
}
|
||
}
|
||
|
||
if (curr.code === 0) break;
|
||
|
||
switch (curr.code) {
|
||
case 2: // 填充图案名
|
||
entity.patternName = curr.value as string;
|
||
break;
|
||
case 70: // 实体填充标志(实体填充 = 1;图案填充 = 0)
|
||
entity.isSolid = curr.value != 0;
|
||
break;
|
||
case 91: // 边界路径(环)数
|
||
numBoundaryLoops = curr.value as number;
|
||
if (numBoundaryLoops > 0) {
|
||
entity.boundaryLoops = []
|
||
}
|
||
break;
|
||
/**
|
||
* 图案填充样式:
|
||
* 0 = 对“奇数奇偶校验”区域进行图案填充(普通样式)
|
||
* 1 = 仅对最外层区域进行图案填充(“外部”样式)
|
||
* 2 = 对整个区域进行图案填充(“忽略”样式)
|
||
*/
|
||
case 75:
|
||
entity.hatchStyle = curr.value as string;
|
||
break;
|
||
/**
|
||
* 填充图案类型:
|
||
* 0 = 用户定义;1 = 预定义;2 = 自定义
|
||
*/
|
||
case 76:
|
||
entity.patternType = curr.value as number;
|
||
break;
|
||
case 52: // 填充图案角度(仅限图案填充)
|
||
entity.patternAngle = (curr.value as number) * Math.PI / 180;
|
||
break;
|
||
case 41: // 填充图案比例或间距(仅限图案填充)
|
||
entity.patternScale = curr.value as number;
|
||
break;
|
||
case 78: // 图案定义直线数
|
||
numDefinitionLines = curr.value as number;
|
||
if (numDefinitionLines > 0) {
|
||
entity.definitionLines = []
|
||
}
|
||
break;
|
||
case 98: // 种子点数
|
||
numSeedPoints = curr.value as number;
|
||
if (numSeedPoints > 0) {
|
||
entity.seedPoints = []
|
||
}
|
||
break;
|
||
default: // 检查通用实体属性
|
||
helpers.checkCommonEntityProperties(entity, curr, scanner);
|
||
break;
|
||
}
|
||
curr = scanner.next();
|
||
}
|
||
|
||
return entity;
|
||
};
|
||
}
|
||
|
||
function ParseBoundaryLoop(curr: IGroup, scanner: DxfArrayScanner) {
|
||
let entity:any = null
|
||
|
||
const ParsePolyline = () => {
|
||
const pl: { vertices: IPoint[], isClosed: boolean } = {vertices: [], isClosed: false};
|
||
let numVertices = 0;
|
||
while (true) {
|
||
if (numVertices > 0) {
|
||
for (let i = 0; i < numVertices; i++) {
|
||
if (curr.code != 10) {
|
||
break
|
||
}
|
||
const p = helpers.parsePoint(scanner)
|
||
curr = scanner.next();
|
||
if (curr.code == 42) {
|
||
// @ts-ignore
|
||
p.bulge = curr.value;
|
||
curr = scanner.next();
|
||
}
|
||
pl.vertices.push(p)
|
||
}
|
||
return pl
|
||
}
|
||
|
||
switch (curr.code) {
|
||
case 73:
|
||
pl.isClosed = curr.value as boolean;
|
||
break;
|
||
case 93:
|
||
numVertices = curr.value as number;
|
||
break;
|
||
default:
|
||
return pl;
|
||
}
|
||
curr = scanner.next();
|
||
}
|
||
}
|
||
|
||
const ParseEdge = () => {
|
||
if (curr.code != 72) {
|
||
return null
|
||
}
|
||
const e:any = {type: curr.value}
|
||
curr = scanner.next();
|
||
const isSpline = e.type == 4;
|
||
|
||
while (true) {
|
||
switch (curr.code) {
|
||
case 10:
|
||
if (isSpline) {
|
||
if (!e.controlPoints) {
|
||
e.controlPoints = [];
|
||
}
|
||
e.controlPoints.push(helpers.parsePoint(scanner));
|
||
} else {
|
||
e.start = helpers.parsePoint(scanner);
|
||
}
|
||
break;
|
||
case 11:
|
||
if (isSpline) {
|
||
if (!e.fitPoints) {
|
||
e.fitPoints = [];
|
||
}
|
||
e.fitPoints.push(helpers.parsePoint(scanner));
|
||
} else {
|
||
e.end = helpers.parsePoint(scanner);
|
||
}
|
||
break;
|
||
case 40:
|
||
if (isSpline) {
|
||
if (!e.knotValues) {
|
||
e.knotValues = [];
|
||
}
|
||
e.knotValues.push(curr.value);
|
||
} else {
|
||
e.radius = curr.value;
|
||
}
|
||
break;
|
||
case 50:
|
||
e.startAngle = (curr.value as number) * Math.PI / 180;
|
||
break;
|
||
case 51:
|
||
e.endAngle = (curr.value as number) * Math.PI / 180;
|
||
break;
|
||
case 73:
|
||
if (isSpline) {
|
||
e.rational = curr.value;
|
||
} else {
|
||
e.isCcw = curr.value;
|
||
}
|
||
break;
|
||
case 74:
|
||
e.periodic = curr.value;
|
||
break;
|
||
case 94:
|
||
e.degreeOfSplineCurve = curr.value;
|
||
break;
|
||
|
||
//XXX暂时忽略一些群体,主要是样条
|
||
case 95:
|
||
case 96:
|
||
case 42:
|
||
case 97:
|
||
break;
|
||
default:
|
||
return e
|
||
}
|
||
curr = scanner.next();
|
||
}
|
||
}
|
||
|
||
let polylineParsed = false;
|
||
let numEdges = 0;
|
||
let numSourceRefs = 0;
|
||
|
||
while (true) {
|
||
if (!entity) {
|
||
if (curr.code != 92) {
|
||
return null;
|
||
}
|
||
entity = {type: curr.value};
|
||
curr = scanner.next();
|
||
}
|
||
|
||
if ((entity.type & 2) && !polylineParsed) {
|
||
entity.polyline = ParsePolyline()
|
||
polylineParsed = true
|
||
}
|
||
|
||
while (numEdges) {
|
||
const edge = ParseEdge();
|
||
if (edge) {
|
||
entity.edges.push(edge);
|
||
numEdges--;
|
||
} else {
|
||
numEdges = 0;
|
||
}
|
||
}
|
||
|
||
while (numSourceRefs) {
|
||
if (curr.code == 330) {
|
||
entity.sourceRefs.push(curr.value);
|
||
numSourceRefs--;
|
||
curr = scanner.next();
|
||
} else {
|
||
numSourceRefs = 0
|
||
}
|
||
}
|
||
|
||
switch (curr.code) {
|
||
case 93:
|
||
numEdges = curr.value as number;
|
||
if (numEdges > 0) {
|
||
entity.edges = []
|
||
}
|
||
break;
|
||
case 97:
|
||
numSourceRefs = curr.value as number;
|
||
if (numSourceRefs > 0) {
|
||
entity.sourceRefs = []
|
||
}
|
||
break;
|
||
default:
|
||
scanner.rewind();
|
||
return entity;
|
||
}
|
||
curr = scanner.next();
|
||
}
|
||
}
|
||
|
||
function ParseDefinitionLine(curr: IGroup, scanner: DxfArrayScanner) {
|
||
/* 假设总是从53组开始. */
|
||
if (curr.code != 53) {
|
||
return null
|
||
}
|
||
const entity:any = {
|
||
angle: (curr.value as number) * Math.PI / 180,
|
||
base: {x: 0, y: 0},
|
||
offset: {x: 0, y: 0}
|
||
};
|
||
curr = scanner.next();
|
||
|
||
let numDashes = 0;
|
||
while (true) {
|
||
switch (curr.code) {
|
||
case 43:
|
||
entity.base.x = curr.value as number;
|
||
break;
|
||
case 44:
|
||
entity.base.y = curr.value as number;
|
||
break;
|
||
case 45:
|
||
entity.offset.x = curr.value as number;
|
||
break;
|
||
case 46:
|
||
entity.offset.y = curr.value as number;
|
||
break;
|
||
case 49:
|
||
if (numDashes > 0) {
|
||
entity.dashes.push(curr.value);
|
||
numDashes--;
|
||
}
|
||
break;
|
||
case 79:
|
||
numDashes = curr.value as number;
|
||
if (curr.value) {
|
||
entity.dashes = []
|
||
}
|
||
break;
|
||
default:
|
||
scanner.rewind();
|
||
return entity;
|
||
}
|
||
curr = scanner.next();
|
||
}
|
||
}
|
||
|
||
function ParseSeedPoint(curr: IGroup, scanner: DxfArrayScanner) {
|
||
if (curr.code != 10) {
|
||
return null
|
||
}
|
||
return helpers.parsePoint(scanner);
|
||
}
|