This repository has been archived by the owner on Jul 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(DXF Deserializer): Adds dxf deserializer and all associated code
* complete DXF deserializer package * helper for comparison of float values * added dxf deserializer to readme files and package lists * closes #10
- Loading branch information
1 parent
6a1cc4b
commit ae4a6c0
Showing
20 changed files
with
3,975 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
/* | ||
## License | ||
Copyright (c) 2017 Z3 Development https://github.com/z3dev | ||
All code released under MIT license | ||
Thanks to @issacs for the sax js library, and inspiration for this reader | ||
*/ | ||
|
||
// DXF reader to emit groups of interest to handlers | ||
|
||
;(function (dxf) { // wrapper for non-node envs | ||
dxf.reader = function (options) { return new DxfReader(options) } | ||
|
||
dxf.STATES = [ | ||
'start', | ||
'end', | ||
'error' | ||
] | ||
|
||
/** | ||
* Class DxfReader | ||
* A class to hold state while reading DXF formatted data. | ||
* @param {Object} [options] - options for parsing | ||
* @param {Boolean} [options.track=true] - track position for error reporting | ||
* @param {Boolean} [options.strict=false] - obey strict DXF specifications | ||
* @constructor | ||
* | ||
* @example | ||
* const dxfPath = path.resolve(__dirname, 'circle10.dxf') | ||
* let src = fs.readFileSync(dxfPath, 'UTF8') | ||
* let reader = dxf.reader({track: true}) | ||
* // setup state handling | ||
* reader.on('error',handleError) | ||
* reader.on('start',handleStart) | ||
* reader.on('end' ,handleEnd) | ||
* // setup handling for groups of interest, skip the rest | ||
* reader.absorb(0,handleEntity) | ||
* // start the reader | ||
* reader.write(src).close() | ||
*/ | ||
function DxfReader (options) { | ||
var reader = this | ||
reader.options = options || {} | ||
|
||
reader.trackPosition = (reader.options.track !== false) | ||
if (reader.trackPosition) { | ||
reader.line = reader.column = reader.c = 0 | ||
} | ||
} | ||
|
||
DxfReader.prototype = { | ||
// set a handler for the given state | ||
// see dxf.STATES above | ||
on: function (state, callback) { | ||
// verify the state | ||
// set the callback | ||
var reader = this | ||
reader['on' + state] = callback | ||
}, | ||
|
||
// set a handler for the given group and value | ||
absorb: function (group, callback) { | ||
if (this.absorbers === undefined) { | ||
this.absorbers = new Map() | ||
} | ||
this.absorbers.set(group, callback) | ||
}, | ||
|
||
// write the given data into the reader, initiating parsing | ||
write: function (data) { | ||
var reader = this | ||
parse(reader, data) | ||
return reader | ||
}, | ||
|
||
// close and clear all state | ||
close: function () { | ||
var reader = this | ||
reader.isclosed = true | ||
return reader | ||
} | ||
} | ||
|
||
// | ||
// emit the start of processing to the onstart handler if any | ||
// | ||
function emitstart (reader) { | ||
return emitstate(reader, 'onstart', reader.data) | ||
} | ||
|
||
// | ||
// emit the group (code and value) to asorbers | ||
// | ||
function emitgroup (reader, group, value) { | ||
// console.log(group+": "+value) | ||
// emit this group to all listeners | ||
if (reader.absorbers !== undefined) { | ||
var absorber = reader.absorbers.get(group) | ||
if (absorber !== undefined) { | ||
absorber(reader, group, value) | ||
} | ||
} | ||
} | ||
|
||
// | ||
// wrap and emit the given error to the onerror handler if any | ||
// | ||
function emiterror (reader, er) { | ||
// closeText(reader) | ||
if (reader.trackPosition) { | ||
er += ` | ||
Line: ${reader.line} | ||
Column: ${reader.column} | ||
Char: ${reader.c}` | ||
} | ||
er = new Error(er) | ||
reader.error = er | ||
return emitstate(reader, 'onerror', er) | ||
} | ||
|
||
// | ||
// emit the end of processing to the onend handler if any | ||
// | ||
function emitend (reader) { | ||
return emitstate(reader, 'onend', reader.data) | ||
} | ||
|
||
function emitstate (reader, state, data) { | ||
var onhandler = state.toString() | ||
reader[onhandler] && reader[onhandler](reader, data) | ||
return reader | ||
} | ||
|
||
// | ||
// parse the given data in the context of the given reader | ||
// | ||
function parse (reader, data) { | ||
// check reader state | ||
if (reader.error) { | ||
throw reader.error // throw the last error | ||
} | ||
if (reader.isclosed) { | ||
return emiterror(reader, 'Cannot write after close') | ||
} | ||
|
||
emitstart(reader) | ||
|
||
if (data === null) { | ||
return emitend(reader) | ||
} | ||
|
||
// initial state to initiate parsing | ||
reader.group = null | ||
reader.value = null | ||
reader.error = null | ||
|
||
reader.position = 0 | ||
reader.line = 0 | ||
reader.column = 0 | ||
|
||
// use or convert the data to String | ||
var i = 0 | ||
var c = '' | ||
var l = '' | ||
while (reader.error === null) { | ||
c = charAt(data, i++) | ||
if (!c) { | ||
break | ||
} | ||
if (reader.trackPosition) { | ||
reader.position++ | ||
if (c === '\n') { | ||
reader.line++ | ||
reader.column = 0 | ||
} else { | ||
reader.column++ | ||
} | ||
} | ||
// dxf files are parsed line by line | ||
if (c === '\n') { | ||
parseLine(reader, l) | ||
l = '' | ||
} else { | ||
l += c | ||
} | ||
} | ||
// emit state change | ||
emitend(reader) | ||
return reader | ||
} | ||
|
||
/** Parse the given line in the context of the given reader, emitting group value pairs | ||
* @param reader {DxfReader} - context DxfReader to use | ||
* @param line {String} - line to parse | ||
*/ | ||
function parseLine (reader, line) { | ||
line = line.trim() | ||
if (reader.group === null) { | ||
setDxfGroup(reader, line) | ||
reader.value = null | ||
} else { | ||
setDxfValue(reader, line) | ||
} | ||
// handle group and value pairs | ||
if (reader.group !== null && reader.value !== null) { | ||
// emit events for group and value pairs | ||
emitgroup(reader, reader.group, reader.value) | ||
|
||
reader.group = null | ||
reader.value = null | ||
} | ||
} | ||
|
||
/** Parse the given line in the context of the given reader, and update the group | ||
* @param reader {DxfReader} - context DxfReader to use | ||
* @param line {String} - line to parse | ||
*/ | ||
function setDxfGroup (reader, line) { | ||
// groups are numeric | ||
var code = parseInt(line) | ||
if (isNaN(code)) { | ||
emiterror(reader, 'Invalid group (int)') | ||
reader.group = null | ||
} else { | ||
reader.group = code | ||
} | ||
} | ||
|
||
/** Parse the given line in the context of the given reader, and update the (group) value | ||
* @param reader {DxfReader} - context DxfReader to use | ||
* @param line {String} - line to parse | ||
*/ | ||
function setDxfValue (reader, line) { | ||
if (reader.options.strict) { | ||
// TODO evaluate the value based on DXF specifications | ||
reader.value = line | ||
} else { | ||
reader.value = line | ||
} | ||
} | ||
|
||
// | ||
// helper function to return expected values | ||
// | ||
function charAt (data, i) { | ||
if (data && data.length > i) { | ||
return data.charAt(i) | ||
} | ||
return '' | ||
} | ||
})(typeof exports === 'undefined' ? this.dxf = {} : exports) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
## @jscad/dxf-deserializer | ||
|
||
> DXF deserializer for the JSCAD project | ||
[](https://badge.fury.io/gh/jscad%40jscad%2Fdxf-deserializer) | ||
[](https://travis-ci.org/jscad/dxf-deserializer) | ||
|
||
## Overview | ||
|
||
This deserializer converts raw DXF data to JSCAD code fragments, or converts raw DXF data directy to CSG library objects. When converting unknown DXF data, converting to JSCAD code fragments will provide more information. | ||
|
||
### DXF Implementation Notes | ||
|
||
The [DXF(tm) file structure](http://docs.autodesk.com/ACD/2014/ENU/files/GUID-73E9E797-3BAA-4795-BBD8-4CE7A03E93CF.htm) changes continously as AutoDesk releases new features and fixes. So, you can imagine that after 20 years, the contents of DXF files are pretty messed up. Expect the worst. | ||
|
||
**NOTE: At this time, only ASCII DXF files are supported. BINARY DXF files are not supported.** | ||
|
||
This deserializer converts only what is required by JSCAD libraries and applications. Full document conversion is NOT supported, so don't even try. However, conversion of the following DXF entities are possible: | ||
|
||
| DXF Entity | CSG Object | Notes | | ||
| --------------- | ---------- | ------ | | ||
| 3DFACE | to CSG | | | ||
| ARC | to Path2D | | | ||
| CIRCLE | to CAG | Start and stop angles are ignored | | ||
| ELLIPSE | to CAG | Start and stop angles are ignored | | ||
| LINE | to Line2D or Line3D | This will change in the future | | ||
| LWPOLYLINE | to Path2D or CAG | Conversion to CAG if LWPOLYLINE is closed | | ||
| MESH | to CSG | | | ||
| POLYLINE (line) | to Path2D or CAG | Conversion to CAG if POLYLINE is closed | | ||
| POLYLINE (mesh) | to CSG | | | ||
| POLYLINE (face) | to CSG | | | ||
|
||
In addition, colors are converted using the AutoCad standard color index (256 colors). | ||
|
||
Finally, there are many applications that can save to DXF formats. All testing is performed with files from AutoCad, period. | ||
|
||
## Table of Contents | ||
|
||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Contribute](#contribute) | ||
- [License](#license) | ||
|
||
|
||
## Installation | ||
|
||
``` | ||
npm install @jscad/dxf-deserializer | ||
``` | ||
|
||
## Usage | ||
|
||
```javascript | ||
const deSerializer = require('@jscad/dxf-deserializer') | ||
|
||
const rawData = fs.readFileSync('PATH/TO/file.dxf') | ||
const jscadCode = deSerializer(rawData) | ||
|
||
``` | ||
|
||
## Contribute | ||
|
||
For questions about the API, please contact the [User Group](https://plus.google.com/communities/114958480887231067224) | ||
|
||
PRs accepted. | ||
|
||
Small Note: If editing this README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. | ||
|
||
## License | ||
|
||
[The MIT License (MIT)](./LICENSE) |
Oops, something went wrong.