Turns out there's a built in way to get line segments out of shapes in OpenRNDR.

Using this I get less points and about the same quality as what I originally intended. Plotting seems to be working. I still need to finish setting up the coordinate system and scaling.
This commit is contained in:
David Diaz 2019-10-26 02:46:43 -06:00
parent fb7613114b
commit 6c06d8ea37
2 changed files with 74 additions and 66 deletions

View File

@ -1,13 +1,11 @@
import com.martianwabbit.HPGL
import com.martianwabbit.logger
import com.martianwabbit.saveToHPGL
import com.martianwabbit.selectPen
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.math.Vector2
import org.openrndr.shape.CompositionDrawer
import java.io.File
import com.martianwabbit.saveToHPGL
import org.openrndr.Configuration
import org.openrndr.Program
fun main() = application {
configure {
@ -18,11 +16,14 @@ fun main() = application {
program {
extend {
val c = CompositionDrawer()
c.circle(Vector2(20.0, 20.0), 12.0)
c.selectPen(1)
c.circle(Vector2(40.0, 40.0), 30.0)
c.rectangle(75.0, 60.0, 80.0, 200.0)
c.lineSegment(Vector2(0.0, 0.0), Vector2(200.0, 200.0))
c.composition.saveToHPGL(File("output.plt"))
this.application.exit()
drawer.background(ColorRGBa.WHITE)
drawer.composition(c.composition)

View File

@ -3,37 +3,74 @@ package com.martianwabbit
import org.openrndr.math.Vector2
import org.openrndr.shape.*
import java.io.File
import java.util.logging.Logger
import kotlin.math.pow
import kotlin.math.sqrt
val logger = Logger.getLogger("")
fun Composition.saveToHPGL(file: File) {
HPGL().generateFromComposition(this)
val plot = HPGL().generateFromComposition(this)
file.writeText(plot)
}
class HPGL(pageSize: PageSize = PageSize.A4) {
fun generateFromComposition(composition: Composition) {
composition.root.traverse { shape ->
if (shape == Stage.Before) {
if (this is ShapeNode) {
this.shape.contours.forEach { shape ->
val i = shape.sampleEquidistant(200)
val rr = StringBuilder()
for (v in i.segments) {
rr.appendln("${v.start.x}, ${v.start.y}")
private var p1: Vector2
private var p2: Vector2
private val resolution = 35
init {
// TODO: Set these according to plotter
when (pageSize) {
PageSize.A3 -> {
p1 = Vector2(0.0, 0.0)
p2 = Vector2(0.0, 0.0)
}
PageSize.A4 -> {
p1 = Vector2(603.0, 521.0)
p2 = Vector2(10603.0, 7721.0)
}
}
}
fun generateFromComposition(composition: Composition): String {
val result = StringBuilder()
result.appendln("IN;") // Initialize the plotter
result.appendln("IP${p1.getCoords()},${p2.getCoords()};") // Setup coordinates
result.appendln("SC0,${p2.div(10.0).x},0,${p2.div(10.0).y};") // Setup coordinates
result.appendln("PA0,0;") // Plot absolutely
composition.root.traverse { stage ->
if (stage == Stage.Before) {
when(this) {
is ShapeNode -> {
this.shape.contours.forEach { shape ->
val segments = shape.sampleLinear().segments
segments.forEachIndexed { i, segment ->
if (i == 0) {
result.appendln("PU${segment.start.getCoords()};") // Go to shape start
result.appendln("PD${segment.end.getCoords()};")
} else {
result.appendln("PD${segment.start.getCoords()};") // PD coordinates for all other segments
result.appendln("PD${segment.end.getCoords()};") // PD coordinates for all other segments
}
}
result.appendln("PU;") // Done plotting
}
calculateSpline(shape.segments)
}
is SelectPen -> {
result.appendln("SP${this.penNumber};")
}
}
}
}
result.appendln("PA0,0")
return result.toString()
}
}
private fun Vector2.distanceTo(point: Vector2): Double {
return sqrt((point.x - this.x).pow(2.0) + (point.y - this.y).pow(2.0))
private fun Vector2.getCoords(): String {
return "$x,$y"
}
enum class PageSize {
@ -49,51 +86,21 @@ private enum class Stage {
private fun CompositionNode.traverse(cb: CompositionNode.(stage: Stage) -> Unit) {
this.cb(Stage.Before)
if (this is GroupNode) {
if (this is GroupNode && this.children.size > 0) {
this.children.forEach { it.traverse(cb) }
}
this.cb(Stage.After)
}
// These default values correspond to a centripetal Catmull-Rom spline
private fun calculateSpline(segments: List<Segment>, resolution: Int = 100, alpha: Double = .5, tension: Double = .0) {
val result = mutableListOf<Vector2>()
segments.forEach {
val points = mutableListOf<Vector2>()
points.add(it.start)
points.addAll(it.control)
points.add(it.end)
class SelectPen(val penNumber: Int) : GroupNode()
class VelocitySelect(val velocity: Int) : GroupNode()
when(points.size) {
4 -> { // Catmull-Rom
val t0 = 0.0
val t1 = t0 + points[0].distanceTo(points[1]).pow(alpha)
val t2 = t1 + points[1].distanceTo(points[2]).pow(alpha)
val t3 = t2 + points[2].distanceTo(points[3]).pow(alpha)
fun CompositionDrawer.selectPen(pen: Int) {
this.root.children.add(SelectPen(pen))
}
val p0 = points[0]
val p1 = points[1]
val p2 = points[2]
val p3 = points[3]
fun CompositionDrawer.velocitySelect(velocity: Int) {
this.root.children.add(VelocitySelect(velocity))
}
val m1 = ((p1 - p0) / (t1 - t0) - (p2 - p0) / (t2 - t0) + (p2 - p1) / (t2 - t1)) * (1.0 - tension) * (t2 - t1)
val m2 = ((p2 - p1) / (t2 - t1) - (p3 - p1) / (t3 - t1) + (p3 - p2) / (t3 - t2)) * (1.0 - tension) * (t2 - t1)
val a = (p1 - p2) + m1 + m2 * 2.0
val b = ((p1 - p2) * -3.0) - m1 - m1 - m2
for (i in 0..100 step 10) {
val t = (i / 100).toDouble()
val r = a * t.pow(3) + b * t.pow(2) + m1 * t.pow(1) + p1
result.add(r)
}
}
}
}
val rr = StringBuilder()
for (v in result) {
rr.appendln("${v.x}, ${v.y}")
}
val a = Vector2(0.0, 10.0).distanceTo(Vector2(13.0, 12.0))
logger.info("done")
}