Example #1
0
// 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
}
Example #2
0
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
		}
	}
}