Skip to content
This repository has been archived by the owner on Jul 24, 2022. It is now read-only.

Commit

Permalink
feat(DXF Deserializer): Adds dxf deserializer and all associated code
Browse files Browse the repository at this point in the history
* complete DXF deserializer package
* helper for comparison of float values
* added dxf deserializer to readme files and package lists
* closes #10
  • Loading branch information
z3dev authored and kaosat-dev committed Feb 24, 2018
1 parent 6a1cc4b commit ae4a6c0
Show file tree
Hide file tree
Showing 20 changed files with 3,975 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ do not generate CSG/CAG objects: there is however work done to enable CSG/CAG ou
deserializers with optional CSG/CAG output:

- [x] amf-deserializer
- [x] dxf-deserializer
- [ ] json-deserializer
- [x] obj-deserializer
- [x] stl-deserializer
- [x] svg-deserializer

Following formats are supported as inputs:
- [AMF](https://github.com/jscad/io/blob/master/packages/amf-deserializer)
- [DXF](https://github.com/jscad/io/blob/master/packages/dxf-deserializer)
- [gcode](https://github.com/jscad/io/blob/master/packages/gcode-deserializer)
- [JSON](https://github.com/jscad/io/blob/master/packages/json-deserializer)
- [OBJ](https://github.com/jscad/io/blob/master/packages/obj-deserializer)
Expand Down
254 changes: 254 additions & 0 deletions packages/dxf-deserializer/DxfReader.js
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)
71 changes: 71 additions & 0 deletions packages/dxf-deserializer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## @jscad/dxf-deserializer

> DXF deserializer for the JSCAD project
[![GitHub version](https://badge.fury.io/gh/jscad%40jscad%2Fdxf-deserializer.svg)](https://badge.fury.io/gh/jscad%40jscad%2Fdxf-deserializer)
[![Build Status](https://travis-ci.org/jscad/io.svg)](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)
Loading

0 comments on commit ae4a6c0

Please sign in to comment.