// parsePolygon parses a polygon. func (p *Parser) parsePolygon( parent elem, lines [][]byte, x, y int, ) error { var pg Polygon pg.X = append(pg.X, float64(x)) pg.Y = append(pg.Y, float64(y)) startX := x startY := y outEdges := outgoingEdges(lines, x, y) switch bit.Count(outEdges) { case 0: return &ParseError{X: x, Y: y, Err: ErrPolyCornerNoEdge} case 1: return &ParseError{X: x, Y: y, Err: ErrPolyCornerOneEdge} case 2: // nothing default: return &ParseError{X: x, Y: y, Err: ErrPolyCornerTooManyEdges} } var edge byte if outEdges&eEdge > 0 { edge = wEdge x++ } else if outEdges&seEdge > 0 { edge = nwEdge x++ y++ } else if outEdges&sEdge > 0 { edge = nEdge y++ } endX, endY, arrowEnd, dotted, endCorner, err := followLine(&pg, lines, x, y, edgeState, edge, false, true) if err != nil { return err } // check final point if endCorner { if endX != startX || endY != startY { return &ParseError{X: startX, Y: startY, Err: ErrPolygonNotClosed} } pg.Dotted = append(pg.Dotted, dotted) // scale pg.scale(p) // add polygon to parent parent.addElem(&pg) } else { // we got a polyline and not a polygon, this is the end var ( pls Polyline // start ple Polyline // end pl Polyline // final ) ple.X = pg.X ple.Y = pg.Y ple.X = append(ple.X, float64(endX)) ple.Y = append(ple.Y, float64(endY)) ple.ArrowEnd = arrowEnd ple.Dotted = pg.Dotted ple.Dotted = append(ple.Dotted, dotted) // go into other direction to get start x, y, arrowEnd, dotted, _, err := followLine(&pls, lines, startX, startY, cornerState, 0, false, false) if err != nil { return err } pls.ArrowEnd = arrowEnd pls.X = append(pls.X, float64(x)) pls.Y = append(pls.Y, float64(y)) pls.Dotted = append(pls.Dotted, dotted) pl.ArrowStart = pls.ArrowEnd pl.ArrowEnd = ple.ArrowEnd for i := len(pls.X) - 1; i >= 0; i-- { pl.X = append(pl.X, pls.X[i]) pl.Y = append(pl.Y, pls.Y[i]) } for i := len(pls.Dotted) - 1; i >= 0; i-- { pl.Dotted = append(pl.Dotted, pls.Dotted[i]) } for i := 0; i < len(ple.X); i++ { pl.X = append(pl.X, ple.X[i]) pl.Y = append(pl.Y, ple.Y[i]) } for i := 0; i < len(ple.Dotted); i++ { pl.Dotted = append(pl.Dotted, ple.Dotted[i]) } // scale pl.scale(p) // add polygon to parent parent.addElem(&pl) } return nil }
func followLine( poly appender, lines [][]byte, x, y int, state, edge byte, dotted, endEmptyCorner bool, ) (outX, outY int, arrowEnd, outDotted, endCorner bool, err error) { for { switch state { case cornerState: lines[y][x] = ' ' // nom nom nom // process corner (+) outEdges := outgoingEdges(lines, x, y) switch bit.Count(outEdges) { case 0: if !endEmptyCorner { return 0, 0, false, false, false, &ParseError{X: x, Y: y, Err: ErrPolyCornerOneEdge} } endCorner = true state = endState case 1: // add segement poly.appendPoint(float64(x), float64(y), dotted) dotted = false // follow edge switch { case outEdges&nEdge > 0: edge = sEdge y-- case outEdges&neEdge > 0: edge = swEdge x++ y-- case outEdges&eEdge > 0: edge = wEdge x++ case outEdges&seEdge > 0: edge = nwEdge x++ y++ case outEdges&sEdge > 0: edge = nEdge y++ case outEdges&swEdge > 0: edge = neEdge x-- y++ case outEdges&wEdge > 0: edge = eEdge x-- case outEdges&nwEdge > 0: edge = seEdge x-- y-- } dotted = startsDotted(lines, x, y, edge) state = edgeState default: // TODO: split return 0, 0, false, false, false, errors.New("poly split not implemented") } case edgeState: next, a, d := procEdge(lines, &x, &y, edge) if a { arrowEnd = true } if d { dotted = true } state = next case endState: lines[y][x] = ' ' // nom nom nom outX = x outY = y outDotted = dotted return } } }