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:
parent
fb7613114b
commit
6c06d8ea37
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
|
||||||
this.shape.contours.forEach { shape ->
|
init {
|
||||||
val i = shape.sampleEquidistant(200)
|
// TODO: Set these according to plotter
|
||||||
val rr = StringBuilder()
|
when (pageSize) {
|
||||||
for (v in i.segments) {
|
PageSize.A3 -> {
|
||||||
rr.appendln("${v.start.x}, ${v.start.y}")
|
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 {
|
private fun Vector2.getCoords(): String {
|
||||||
return sqrt((point.x - this.x).pow(2.0) + (point.y - this.y).pow(2.0))
|
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()
|
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CompositionDrawer.velocitySelect(velocity: Int) {
|
||||||
|
this.root.children.add(VelocitySelect(velocity))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue