New segments can be added in the middle of a sketch (#1953)

* get branch up to where it was before

* setup dots properly

* only show extra handle on hover

* use partical texture for plus button

* fix regression

* fix deleted line

* fix sketch on face test

* caluclate segment length in screen-space/in-pixels

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* side small segment handles on resize

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Make sure this works on setup and update of segments

* Add to tangential arcs

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)"

This reverts commit 5dc1adacae.

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)"

This reverts commit b8ceea179c.

* try and fix sketch on face in CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* more test fix

* convert scaling to be based on pixels

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger ci

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)"

This reverts commit 6287c943dd.

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)"

This reverts commit 1baa3819db.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Update src/clientSideScene/segments.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* reduce line thickness

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger CI

* try putting init script back in

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
This commit is contained in:
Kurt Hutten
2024-04-03 13:22:56 +11:00
committed by GitHub
parent 221f037eaa
commit b045a89854
22 changed files with 484 additions and 67 deletions

View File

@ -12,15 +12,22 @@ import {
Mesh,
MeshBasicMaterial,
NormalBufferAttributes,
Points,
PointsMaterial,
Shape,
SphereGeometry,
Texture,
Vector2,
Vector3,
} from 'three'
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'
import { PathToNode, SketchGroup, getTangentialArcToInfo } from 'lang/wasm'
import {
EXTRA_SEGMENT_HANDLE,
EXTRA_SEGMENT_OFFSET_PX,
MIN_SEGMENT_LENGTH,
PROFILE_START,
SEGMENT_WIDTH_PX,
STRAIGHT_SEGMENT,
STRAIGHT_SEGMENT_BODY,
STRAIGHT_SEGMENT_DASH,
@ -44,7 +51,7 @@ export function profileStart({
}) {
const group = new Group()
const geometry = new BoxGeometry(0.8, 0.8, 0.8)
const geometry = new BoxGeometry(12, 12, 12) // in pixels scaled later
const body = new MeshBasicMaterial({ color: 0xffffff })
const mesh = new Mesh(geometry, body)
@ -71,6 +78,7 @@ export function straightSegment({
isDraftSegment,
scale = 1,
callExpName,
texture,
}: {
from: Coords2d
to: Coords2d
@ -79,12 +87,13 @@ export function straightSegment({
isDraftSegment?: boolean
scale?: number
callExpName: string
texture: Texture
}): Group {
const group = new Group()
const shape = new Shape()
shape.moveTo(0, -0.08 * scale)
shape.lineTo(0, 0.08 * scale) // The width of the line
shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale)
shape.lineTo(0, (SEGMENT_WIDTH_PX / 2) * scale)
let geometry
if (isDraftSegment) {
@ -122,24 +131,44 @@ export function straightSegment({
}
group.name = STRAIGHT_SEGMENT
const length = Math.sqrt(
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
)
const arrowGroup = createArrowhead(scale)
arrowGroup.position.set(to[0], to[1], 0)
const dir = new Vector3()
.subVectors(new Vector3(to[0], to[1], 0), new Vector3(from[0], from[1], 0))
.normalize()
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
const pxLength = length / scale
const shouldHide = pxLength < MIN_SEGMENT_LENGTH
arrowGroup.visible = !shouldHide
group.add(mesh)
if (callExpName !== 'close') group.add(arrowGroup)
const extraSegmentGroup = createExtraSegmentHandle(scale, texture)
const offsetFromBase = new Vector2(to[0] - from[0], to[1] - from[1])
.normalize()
.multiplyScalar(EXTRA_SEGMENT_OFFSET_PX * scale)
extraSegmentGroup.position.set(
from[0] + offsetFromBase.x,
from[1] + offsetFromBase.y,
0
)
extraSegmentGroup.visible = !shouldHide
group.add(extraSegmentGroup)
return group
}
function createArrowhead(scale = 1): Group {
const arrowMaterial = new MeshBasicMaterial({ color: 0xffffff })
const arrowheadMesh = new Mesh(new ConeGeometry(0.31, 1.5, 12), arrowMaterial)
arrowheadMesh.position.set(0, -0.6, 0)
const sphereMesh = new Mesh(new SphereGeometry(0.27, 12, 12), arrowMaterial)
// specify the size of the geometry in pixels (i.e. cone height = 20px, cone radius = 4.5px)
// we'll scale the group to the correct size later to match these sizes in screen space
const arrowheadMesh = new Mesh(new ConeGeometry(4.5, 20, 12), arrowMaterial)
arrowheadMesh.position.set(0, -9, 0)
const sphereMesh = new Mesh(new SphereGeometry(4, 12, 12), arrowMaterial)
const arrowGroup = new Group()
arrowGroup.userData.type = ARROWHEAD
@ -150,6 +179,36 @@ function createArrowhead(scale = 1): Group {
return arrowGroup
}
function createExtraSegmentHandle(scale: number, texture: Texture): Group {
const particleMaterial = new PointsMaterial({
size: 12, // in pixels
map: texture,
transparent: true,
opacity: 0,
depthTest: false,
})
const mat = new MeshBasicMaterial({
transparent: true,
color: 0xffffff,
opacity: 0,
})
const particleGeometry = new BufferGeometry().setFromPoints([
new Vector3(0, 0, 0),
])
const sphereMesh = new Mesh(new SphereGeometry(6, 12, 12), mat) // sphere radius in pixels
const particle = new Points(particleGeometry, particleMaterial)
particle.userData.ignoreColorChange = true
particle.userData.type = EXTRA_SEGMENT_HANDLE
const extraSegmentGroup = new Group()
extraSegmentGroup.userData.type = EXTRA_SEGMENT_HANDLE
extraSegmentGroup.name = EXTRA_SEGMENT_HANDLE
extraSegmentGroup.add(sphereMesh)
extraSegmentGroup.add(particle)
extraSegmentGroup.scale.set(scale, scale, scale)
return extraSegmentGroup
}
export function tangentialArcToSegment({
prevSegment,
from,
@ -158,6 +217,7 @@ export function tangentialArcToSegment({
pathToNode,
isDraftSegment,
scale = 1,
texture,
}: {
prevSegment: SketchGroup['value'][number]
from: Coords2d
@ -166,6 +226,7 @@ export function tangentialArcToSegment({
pathToNode: PathToNode
isDraftSegment?: boolean
scale?: number
texture: Texture
}): Group {
const group = new Group()
@ -178,12 +239,13 @@ export function tangentialArcToSegment({
)
: prevSegment.from
const { center, radius, startAngle, endAngle, ccw } = getTangentialArcToInfo({
arcStartPoint: from,
arcEndPoint: to,
tanPreviousPoint: previousPoint,
obtuse: true,
})
const { center, radius, startAngle, endAngle, ccw, arcLength } =
getTangentialArcToInfo({
arcStartPoint: from,
arcEndPoint: to,
tanPreviousPoint: previousPoint,
obtuse: true,
})
const geometry = createArcGeometry({
center,
@ -219,8 +281,28 @@ export function tangentialArcToSegment({
new Vector3(0, 1, 0),
new Vector3(Math.cos(arrowheadAngle), Math.sin(arrowheadAngle), 0)
)
const pxLength = arcLength / scale
const shouldHide = pxLength < MIN_SEGMENT_LENGTH
arrowGroup.visible = !shouldHide
group.add(mesh, arrowGroup)
const extraSegmentGroup = createExtraSegmentHandle(scale, texture)
const circumferenceInPx = (2 * Math.PI * radius) / scale
const extraSegmentAngleDelta =
(EXTRA_SEGMENT_OFFSET_PX / circumferenceInPx) * Math.PI * 2
const extraSegmentAngle = startAngle + (ccw ? 1 : -1) * extraSegmentAngleDelta
const extraSegmentOffset = new Vector2(
Math.cos(extraSegmentAngle) * radius,
Math.sin(extraSegmentAngle) * radius
)
extraSegmentGroup.position.set(
center[0] + extraSegmentOffset.x,
center[1] + extraSegmentOffset.y,
0
)
extraSegmentGroup.visible = !shouldHide
group.add(mesh, arrowGroup, extraSegmentGroup)
return group
}
@ -242,8 +324,8 @@ export function createArcGeometry({
isDashed?: boolean
scale?: number
}): BufferGeometry {
const dashSize = 1.2 * scale
const gapSize = 1.2 * scale
const dashSizePx = 18 * scale
const gapSizePx = 18 * scale
const arcStart = new EllipseCurve(
center[0],
center[1],
@ -265,8 +347,8 @@ export function createArcGeometry({
0
)
const shape = new Shape()
shape.moveTo(0, -0.08 * scale)
shape.lineTo(0, 0.08 * scale) // The width of the line
shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale)
shape.lineTo(0, (SEGMENT_WIDTH_PX / 2) * scale) // The width of the line
if (!isDashed) {
const points = arcStart.getPoints(50)
@ -281,7 +363,7 @@ export function createArcGeometry({
}
const length = arcStart.getLength()
const totalDashes = length / (dashSize + gapSize) // rounding makes the dashes jittery since the new dash is suddenly appears instead of growing into place
const totalDashes = length / (dashSizePx + gapSizePx) // rounding makes the dashes jittery since the new dash is suddenly appears instead of growing into place
const dashesAtEachEnd = Math.min(100, totalDashes / 2) // Assuming we want 50 dashes total, 25 at each end
const dashGeometries = []
@ -289,8 +371,8 @@ export function createArcGeometry({
// Function to create a dash at a specific t value (0 to 1 along the curve)
const createDashAt = (t: number, curve: EllipseCurve) => {
const startVec = curve.getPoint(t)
const endVec = curve.getPoint(Math.min(0.5, t + dashSize / length))
const midVec = curve.getPoint(Math.min(0.5, t + dashSize / length / 2))
const endVec = curve.getPoint(Math.min(0.5, t + dashSizePx / length))
const midVec = curve.getPoint(Math.min(0.5, t + dashSizePx / length / 2))
const dashCurve = new CurvePath<Vector3>()
dashCurve.add(
new CatmullRomCurve3([
@ -314,7 +396,8 @@ export function createArcGeometry({
}
// fill in the remaining arc
const remainingArcLength = length - dashesAtEachEnd * 2 * (dashSize + gapSize)
const remainingArcLength =
length - dashesAtEachEnd * 2 * (dashSizePx + gapSizePx)
if (remainingArcLength > 0) {
const remainingArcStartT = dashesAtEachEnd / totalDashes
const remainingArcEndT = 1 - remainingArcStartT
@ -359,8 +442,8 @@ export function dashedStraight(
shape: Shape,
scale = 1
): BufferGeometry<NormalBufferAttributes> {
const dashSize = 1.2 * scale
const gapSize = 1.2 * scale // todo: gabSize is not respected
const dashSize = 18 * scale
const gapSize = 18 * scale // TODO: gapSize is not respected
const dashLine = new LineCurve3(
new Vector3(from[0], from[1], 0),
new Vector3(to[0], to[1], 0)