From 6c06d8ea371c9036879ea8550ae3d3f5be54affb Mon Sep 17 00:00:00 2001 From: David Diaz Date: Sat, 26 Oct 2019 02:46:43 -0600 Subject: [PATCH] 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. --- src/main/kotlin/TemplateProgram.kt | 15 ++- .../kotlin/com/martianwabbit/hpglWriter.kt | 125 +++++++++--------- 2 files changed, 74 insertions(+), 66 deletions(-) diff --git a/src/main/kotlin/TemplateProgram.kt b/src/main/kotlin/TemplateProgram.kt index 49f7845..2fa1562 100644 --- a/src/main/kotlin/TemplateProgram.kt +++ b/src/main/kotlin/TemplateProgram.kt @@ -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) diff --git a/src/main/kotlin/com/martianwabbit/hpglWriter.kt b/src/main/kotlin/com/martianwabbit/hpglWriter.kt index d1dedb9..04a7400 100644 --- a/src/main/kotlin/com/martianwabbit/hpglWriter.kt +++ b/src/main/kotlin/com/martianwabbit/hpglWriter.kt @@ -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, resolution: Int = 100, alpha: Double = .5, tension: Double = .0) { - val result = mutableListOf() - segments.forEach { - val points = mutableListOf() - 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") -} \ No newline at end of file