Implement cone surface as a partial fix for #39
This commit is contained in:
parent
3a87e43483
commit
ff80629f24
@ -1,9 +1,7 @@
|
|||||||
package space.kscience.visionforge.examples
|
package space.kscience.visionforge.examples
|
||||||
|
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.gdml.Gdml
|
import space.kscience.gdml.GdmlShowCase
|
||||||
import space.kscience.gdml.LUnit
|
|
||||||
import space.kscience.gdml.decodeFromStream
|
|
||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
import space.kscience.visionforge.html.ResourceLocation
|
import space.kscience.visionforge.html.ResourceLocation
|
||||||
import space.kscience.visionforge.solid.Solids
|
import space.kscience.visionforge.solid.Solids
|
||||||
@ -14,9 +12,7 @@ fun main() {
|
|||||||
}
|
}
|
||||||
context.makeVisionFile(resourceLocation = ResourceLocation.EMBED) {
|
context.makeVisionFile(resourceLocation = ResourceLocation.EMBED) {
|
||||||
vision("canvas") {
|
vision("canvas") {
|
||||||
Gdml.decodeFromStream(javaClass.getResourceAsStream("/gdml/babyIAXO.gdml")!!, true).toVision {
|
GdmlShowCase.babyIaxo().toVision()
|
||||||
lUnit = LUnit.MM
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -187,12 +187,29 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
solid.deltaphi * aScale,
|
solid.deltaphi * aScale,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
is GdmlCone -> cone(solid.rmax1, solid.z, solid.rmax2, name = name) {
|
is GdmlCone -> if (solid.rmin1.toDouble() == 0.0 && solid.rmin2.toDouble() == 0.0) {
|
||||||
require(solid.rmin1 == 0.0) { "Empty cones are not supported" }
|
cone(
|
||||||
require(solid.rmin2 == 0.0) { "Empty cones are not supported" }
|
bottomRadius = solid.rmax1,
|
||||||
|
height = solid.z,
|
||||||
|
upperRadius = solid.rmax2,
|
||||||
|
name = name
|
||||||
|
) {
|
||||||
startAngle = solid.startphi.toFloat()
|
startAngle = solid.startphi.toFloat()
|
||||||
angle = solid.deltaphi.toFloat()
|
angle = solid.deltaphi.toFloat()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
coneSurface(
|
||||||
|
bottomOuterRadius = solid.rmax1,
|
||||||
|
bottomInnerRadius = solid.rmin1,
|
||||||
|
height = solid.z,
|
||||||
|
topOuterRadius = solid.rmax2,
|
||||||
|
topInnerRadius = solid.rmin2,
|
||||||
|
name = name
|
||||||
|
) {
|
||||||
|
startAngle = solid.startphi.toFloat()
|
||||||
|
angle = solid.deltaphi.toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
is GdmlXtru -> extrude(name) {
|
is GdmlXtru -> extrude(name) {
|
||||||
shape {
|
shape {
|
||||||
solid.vertices.forEach {
|
solid.vertices.forEach {
|
||||||
@ -396,7 +413,8 @@ private class GdmlTransformer(val settings: GdmlTransformerSettings) {
|
|||||||
return final
|
return final
|
||||||
}
|
}
|
||||||
|
|
||||||
fun transform(root: Gdml): SolidGroup = finalize(volume(root, root.world.resolve(root) ?: error("GDML root is not resolved")))
|
fun transform(root: Gdml): SolidGroup =
|
||||||
|
finalize(volume(root, root.world.resolve(root) ?: error("GDML root is not resolved")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import kotlin.math.cos
|
|||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cylinder or cut cone segment
|
* A solid cylinder or cut cone segment
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("solid.cone")
|
@SerialName("solid.cone")
|
||||||
|
@ -10,22 +10,24 @@ import kotlin.math.cos
|
|||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Straight tube segment
|
* A conical or cylindrical surface
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("solid.tube")
|
@SerialName("solid.coneSurface")
|
||||||
public class Tube(
|
public class ConeSurface(
|
||||||
public var radius: Float,
|
public var bottomRadius: Float,
|
||||||
|
public var bottomInnerRadius: Float,
|
||||||
public var height: Float,
|
public var height: Float,
|
||||||
public var innerRadius: Float = 0f,
|
public var topRadius: Float,
|
||||||
|
public var topInnerRadius: Float,
|
||||||
public var startAngle: Float = 0f,
|
public var startAngle: Float = 0f,
|
||||||
public var angle: Float = PI2,
|
public var angle: Float = PI2,
|
||||||
) : SolidBase(), GeometrySolid {
|
) : SolidBase(), GeometrySolid {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(radius > 0)
|
require(bottomRadius > 0) { "Cone surface bottom radius must be positive" }
|
||||||
require(height > 0)
|
require(height > 0) { "Cone surface height must be positive" }
|
||||||
require(innerRadius >= 0)
|
require(bottomInnerRadius >= 0) { "Cone surface bottom inner radius must be non-negative" }
|
||||||
//require(startAngle >= 0)
|
//require(startAngle >= 0)
|
||||||
require(angle in (0f..(PI2)))
|
require(angle in (0f..(PI2)))
|
||||||
}
|
}
|
||||||
@ -44,8 +46,8 @@ public class Tube(
|
|||||||
geometryBuilder.apply {
|
geometryBuilder.apply {
|
||||||
|
|
||||||
//creating shape in x-y plane with z = 0
|
//creating shape in x-y plane with z = 0
|
||||||
val bottomOuterPoints = shape(radius, -height / 2)
|
val bottomOuterPoints = shape(bottomRadius, -height / 2)
|
||||||
val upperOuterPoints = shape(radius, height / 2)
|
val upperOuterPoints = shape(topRadius, height / 2)
|
||||||
//outer face
|
//outer face
|
||||||
(1 until segments).forEach {
|
(1 until segments).forEach {
|
||||||
face4(bottomOuterPoints[it - 1], bottomOuterPoints[it], upperOuterPoints[it], upperOuterPoints[it - 1])
|
face4(bottomOuterPoints[it - 1], bottomOuterPoints[it], upperOuterPoints[it], upperOuterPoints[it - 1])
|
||||||
@ -54,7 +56,7 @@ public class Tube(
|
|||||||
if (angle == PI2) {
|
if (angle == PI2) {
|
||||||
face4(bottomOuterPoints.last(), bottomOuterPoints[0], upperOuterPoints[0], upperOuterPoints.last())
|
face4(bottomOuterPoints.last(), bottomOuterPoints[0], upperOuterPoints[0], upperOuterPoints.last())
|
||||||
}
|
}
|
||||||
if (innerRadius == 0f) {
|
if (bottomInnerRadius == 0f) {
|
||||||
val zeroBottom = Point3D(0f, 0f, 0f)
|
val zeroBottom = Point3D(0f, 0f, 0f)
|
||||||
val zeroTop = Point3D(0f, 0f, height)
|
val zeroTop = Point3D(0f, 0f, height)
|
||||||
(1 until segments).forEach {
|
(1 until segments).forEach {
|
||||||
@ -69,8 +71,8 @@ public class Tube(
|
|||||||
face4(zeroTop, zeroBottom, bottomOuterPoints.last(), upperOuterPoints.last())
|
face4(zeroTop, zeroBottom, bottomOuterPoints.last(), upperOuterPoints.last())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val bottomInnerPoints = shape(innerRadius, -height / 2)
|
val bottomInnerPoints = shape(bottomInnerRadius, -height / 2)
|
||||||
val upperInnerPoints = shape(innerRadius, height / 2)
|
val upperInnerPoints = shape(topInnerRadius, height / 2)
|
||||||
//outer face
|
//outer face
|
||||||
(1 until segments).forEach {
|
(1 until segments).forEach {
|
||||||
// inner surface
|
// inner surface
|
||||||
@ -116,24 +118,41 @@ public class Tube(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public inline fun VisionContainerBuilder<Solid>.tube(
|
public inline fun VisionContainerBuilder<Solid>.tube(
|
||||||
r: Number,
|
r: Number,
|
||||||
height: Number,
|
height: Number,
|
||||||
innerRadius: Number = 0f,
|
innerRadius: Number,
|
||||||
startAngle: Number = 0f,
|
startAngle: Number = 0f,
|
||||||
angle: Number = 2 * PI,
|
angle: Number = 2 * PI,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
block: Tube.() -> Unit = {},
|
block: ConeSurface.() -> Unit = {},
|
||||||
): Tube = Tube(
|
): ConeSurface = ConeSurface(
|
||||||
r.toFloat(),
|
bottomRadius = r.toFloat(),
|
||||||
height.toFloat(),
|
bottomInnerRadius = innerRadius.toFloat(),
|
||||||
innerRadius.toFloat(),
|
height = height.toFloat(),
|
||||||
startAngle.toFloat(),
|
topRadius = r.toFloat(),
|
||||||
angle.toFloat()
|
topInnerRadius = innerRadius.toFloat(),
|
||||||
).apply(
|
startAngle = startAngle.toFloat(),
|
||||||
block
|
angle = angle.toFloat()
|
||||||
).also { set(name, it) }
|
).apply(block).also { set(name, it) }
|
||||||
|
|
||||||
|
@VisionBuilder
|
||||||
|
public inline fun VisionContainerBuilder<Solid>.coneSurface(
|
||||||
|
bottomOuterRadius: Number,
|
||||||
|
bottomInnerRadius: Number,
|
||||||
|
height: Number,
|
||||||
|
topOuterRadius: Number,
|
||||||
|
topInnerRadius: Number,
|
||||||
|
name: String? = null,
|
||||||
|
block: ConeSurface.() -> Unit = {},
|
||||||
|
): ConeSurface = ConeSurface(
|
||||||
|
bottomRadius = bottomOuterRadius.toFloat(),
|
||||||
|
bottomInnerRadius = bottomInnerRadius.toFloat(),
|
||||||
|
height = height.toFloat(),
|
||||||
|
topRadius = topOuterRadius.toFloat(),
|
||||||
|
topInnerRadius = topInnerRadius.toFloat(),
|
||||||
|
).apply(block).also { set(name, it) }
|
@ -29,9 +29,9 @@ public class Solids(meta: Meta) : VisionPlugin(meta) {
|
|||||||
subclass(SolidGroup.serializer())
|
subclass(SolidGroup.serializer())
|
||||||
subclass(SolidReferenceGroup.serializer())
|
subclass(SolidReferenceGroup.serializer())
|
||||||
subclass(Composite.serializer())
|
subclass(Composite.serializer())
|
||||||
subclass(Tube.serializer())
|
|
||||||
subclass(Box.serializer())
|
subclass(Box.serializer())
|
||||||
subclass(ConeSegment.serializer())
|
subclass(ConeSegment.serializer())
|
||||||
|
subclass(ConeSurface.serializer())
|
||||||
subclass(Convex.serializer())
|
subclass(Convex.serializer())
|
||||||
subclass(Extruded.serializer())
|
subclass(Extruded.serializer())
|
||||||
subclass(PolyLine.serializer())
|
subclass(PolyLine.serializer())
|
||||||
|
@ -89,6 +89,7 @@ public class ThreeCanvas(
|
|||||||
width = "100%"
|
width = "100%"
|
||||||
height = "100%"
|
height = "100%"
|
||||||
display = "block"
|
display = "block"
|
||||||
|
zIndex = "1000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +127,7 @@ public class ThreeCanvas(
|
|||||||
mousePosition.x = ((event.clientX - rect.left) / canvas.clientWidth) * 2 - 1
|
mousePosition.x = ((event.clientX - rect.left) / canvas.clientWidth) * 2 - 1
|
||||||
mousePosition.y = -((event.clientY - rect.top) / canvas.clientHeight) * 2 + 1
|
mousePosition.y = -((event.clientY - rect.top) / canvas.clientHeight) * 2 + 1
|
||||||
}
|
}
|
||||||
|
event.preventDefault()
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
canvas.onresize = {
|
canvas.onresize = {
|
||||||
|
@ -2,18 +2,18 @@ package space.kscience.visionforge.solid.three
|
|||||||
|
|
||||||
import info.laht.threekt.core.BufferGeometry
|
import info.laht.threekt.core.BufferGeometry
|
||||||
import info.laht.threekt.geometries.CylinderBufferGeometry
|
import info.laht.threekt.geometries.CylinderBufferGeometry
|
||||||
import space.kscience.visionforge.solid.ConeSegment
|
import space.kscience.visionforge.solid.ConeSurface
|
||||||
import space.kscience.visionforge.solid.detail
|
import space.kscience.visionforge.solid.detail
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
public object ThreeCylinderFactory : MeshThreeFactory<ConeSegment>(ConeSegment::class) {
|
public object ThreeCylinderFactory : MeshThreeFactory<ConeSurface>(ConeSurface::class) {
|
||||||
override fun buildGeometry(obj: ConeSegment): BufferGeometry {
|
override fun buildGeometry(obj: ConeSurface): BufferGeometry {
|
||||||
val cylinder = obj.detail?.let {
|
val cylinder = obj.detail?.let {
|
||||||
val segments = it.toDouble().pow(0.5).toInt()
|
val segments = it.toDouble().pow(0.5).toInt()
|
||||||
CylinderBufferGeometry(
|
CylinderBufferGeometry(
|
||||||
radiusTop = obj.upperRadius,
|
radiusTop = obj.topRadius,
|
||||||
radiusBottom = obj.radius,
|
radiusBottom = obj.bottomRadius,
|
||||||
height = obj.height,
|
height = obj.height,
|
||||||
radialSegments = segments,
|
radialSegments = segments,
|
||||||
heightSegments = segments,
|
heightSegments = segments,
|
||||||
@ -22,8 +22,8 @@ public object ThreeCylinderFactory : MeshThreeFactory<ConeSegment>(ConeSegment::
|
|||||||
thetaLength = obj.angle
|
thetaLength = obj.angle
|
||||||
)
|
)
|
||||||
} ?: CylinderBufferGeometry(
|
} ?: CylinderBufferGeometry(
|
||||||
radiusTop = obj.upperRadius,
|
radiusTop = obj.topRadius,
|
||||||
radiusBottom = obj.radius,
|
radiusBottom = obj.bottomRadius,
|
||||||
height = obj.height,
|
height = obj.height,
|
||||||
openEnded = false,
|
openEnded = false,
|
||||||
thetaStart = obj.startAngle,
|
thetaStart = obj.startAngle,
|
||||||
|
@ -35,7 +35,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
objectFactories[Box::class] = ThreeBoxFactory
|
objectFactories[Box::class] = ThreeBoxFactory
|
||||||
objectFactories[Convex::class] = ThreeConvexFactory
|
objectFactories[Convex::class] = ThreeConvexFactory
|
||||||
objectFactories[Sphere::class] = ThreeSphereFactory
|
objectFactories[Sphere::class] = ThreeSphereFactory
|
||||||
objectFactories[ConeSegment::class] = ThreeCylinderFactory
|
objectFactories[ConeSurface::class] = ThreeCylinderFactory
|
||||||
objectFactories[PolyLine::class] = ThreeLineFactory
|
objectFactories[PolyLine::class] = ThreeLineFactory
|
||||||
objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory
|
objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user