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.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.CompositionDrawer import org.openrndr.shape.CompositionDrawer
import java.io.File import java.io.File
import com.martianwabbit.saveToHPGL
import org.openrndr.Configuration
import org.openrndr.Program
fun main() = application { fun main() = application {
configure { configure {
@ -18,11 +16,14 @@ fun main() = application {
program { program {
extend { extend {
val c = CompositionDrawer() 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")) c.composition.saveToHPGL(File("output.plt"))
this.application.exit() this.application.exit()
drawer.background(ColorRGBa.WHITE) drawer.background(ColorRGBa.WHITE)
drawer.composition(c.composition) drawer.composition(c.composition)

View File

@ -3,37 +3,74 @@ package com.martianwabbit
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.* import org.openrndr.shape.*
import java.io.File 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) { fun Composition.saveToHPGL(file: File) {
HPGL().generateFromComposition(this) val plot = HPGL().generateFromComposition(this)
file.writeText(plot)
} }
class HPGL(pageSize: PageSize = PageSize.A4) { class HPGL(pageSize: PageSize = PageSize.A4) {
fun generateFromComposition(composition: Composition) { private var p1: Vector2
composition.root.traverse { shape -> private var p2: Vector2
if (shape == Stage.Before) { private val resolution = 35
if (this is ShapeNode) {
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 -> this.shape.contours.forEach { shape ->
val i = shape.sampleEquidistant(200) val segments = shape.sampleLinear().segments
val rr = StringBuilder() segments.forEachIndexed { i, segment ->
for (v in i.segments) { if (i == 0) {
rr.appendln("${v.start.x}, ${v.start.y}") result.appendln("PU${segment.start.getCoords()};") // Go to shape start
} result.appendln("PD${segment.end.getCoords()};")
calculateSpline(shape.segments) } 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
}
}
is SelectPen -> {
result.appendln("SP${this.penNumber};")
} }
} }
} }
} }
private fun Vector2.distanceTo(point: Vector2): Double { result.appendln("PA0,0")
return sqrt((point.x - this.x).pow(2.0) + (point.y - this.y).pow(2.0)) return result.toString()
}
}
private fun Vector2.getCoords(): String {
return "$x,$y"
} }
enum class PageSize { enum class PageSize {
@ -49,51 +86,21 @@ private enum class Stage {
private fun CompositionNode.traverse(cb: CompositionNode.(stage: Stage) -> Unit) { private fun CompositionNode.traverse(cb: CompositionNode.(stage: Stage) -> Unit) {
this.cb(Stage.Before) this.cb(Stage.Before)
if (this is GroupNode) { if (this is GroupNode && this.children.size > 0) {
this.children.forEach { it.traverse(cb) } this.children.forEach { it.traverse(cb) }
} }
this.cb(Stage.After)
} }
// These default values correspond to a centripetal Catmull-Rom spline class SelectPen(val penNumber: Int) : GroupNode()
private fun calculateSpline(segments: List<Segment>, resolution: Int = 100, alpha: Double = .5, tension: Double = .0) { class VelocitySelect(val velocity: Int) : GroupNode()
val result = mutableListOf<Vector2>()
segments.forEach {
val points = mutableListOf<Vector2>()
points.add(it.start)
points.addAll(it.control)
points.add(it.end)
when(points.size) { fun CompositionDrawer.selectPen(pen: Int) {
4 -> { // Catmull-Rom this.root.children.add(SelectPen(pen))
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)
val p0 = points[0]
val p1 = points[1]
val p2 = points[2]
val p3 = points[3]
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() fun CompositionDrawer.velocitySelect(velocity: Int) {
for (v in result) { this.root.children.add(VelocitySelect(velocity))
rr.appendln("${v.x}, ${v.y}")
}
val a = Vector2(0.0, 10.0).distanceTo(Vector2(13.0, 12.0))
logger.info("done")
} }