Change perpendicular-distance constraint to something more intuitive to setting parallel distance (#110)

* some clean up

* Change perpendicular-distance constraint to something more intuitive to setting parallel distance

* delete

* add back

* force rename

* change name back

* try renaming again
This commit is contained in:
Kurt Hutten
2023-04-08 14:16:49 +10:00
committed by GitHub
parent 0fa56c3f15
commit 2fc68e7c82
10 changed files with 146 additions and 23 deletions

View File

@ -7,10 +7,10 @@ import { EqualLength } from './components/Toolbar/EqualLength'
import { EqualAngle } from './components/Toolbar/EqualAngle'
import { Intersect } from './components/Toolbar/Intersect'
import { SetHorzVertDistance } from './components/Toolbar/SetHorzVertDistance'
import { SetAngleLength } from './components/Toolbar/SetAngleLength'
import { SetAngleLength } from './components/Toolbar/setAngleLength'
import { ConvertToVariable } from './components/Toolbar/ConvertVariable'
import { SetAbsDistance } from './components/Toolbar/SetAbsDistance'
import { SetAngleBetween } from './components/Toolbar/setAngleBetween'
import { SetAngleBetween } from './components/Toolbar/SetAngleBetween'
export const Toolbar = () => {
const {

View File

@ -79,6 +79,7 @@ function stringSplice(str: string, index: number, count: number, add: string) {
return str.slice(0, index) + (add || '') + str.slice(index + count)
}
// what a terriable name
export function useCalc({
value,
initialVariableName: valueName = '',

View File

@ -9,6 +9,7 @@ import {
import {
getNodePathFromSourceRange,
getNodeFromPath,
isLinesParallelAndConstrained,
} from '../../lang/queryAst'
import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints'
import {
@ -17,10 +18,7 @@ import {
getTransformInfos,
} from '../../lang/std/sketchcombos'
import { GetInfoModal } from '../SetHorVertDistanceModal'
import {
createIdentifier,
createVariableDeclaration,
} from '../../lang/modifyAst'
import { createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
const getModalInfo = create(GetInfoModal as any)
@ -37,9 +35,45 @@ export const Intersect = () => {
)
const [enable, setEnable] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
const [forecdSelectionRanges, setForcedSelectionRanges] =
useState<typeof selectionRanges>()
useEffect(() => {
if (!ast) return
const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
if (selectionRanges.codeBasedSelections.length < 2) {
setEnable(false)
setForcedSelectionRanges({ ...selectionRanges })
return
}
const previousSegment =
selectionRanges.codeBasedSelections.length > 1 &&
isLinesParallelAndConstrained(
ast,
programMemory,
selectionRanges.codeBasedSelections[0],
selectionRanges.codeBasedSelections[1]
)
const shouldUsePreviousSegment =
selectionRanges.codeBasedSelections?.[1]?.type !== 'line-end' &&
previousSegment &&
previousSegment.isParallelAndConstrained
console.log(shouldUsePreviousSegment)
const _forcedSelectionRanges: typeof selectionRanges = {
...selectionRanges,
codeBasedSelections: [
selectionRanges.codeBasedSelections?.[0],
shouldUsePreviousSegment
? {
range: previousSegment.sourceRange,
type: 'line-end',
}
: selectionRanges.codeBasedSelections?.[1],
],
}
setForcedSelectionRanges(_forcedSelectionRanges)
const paths = _forcedSelectionRanges.codeBasedSelections.map(({ range }) =>
getNodePathFromSourceRange(ast, range)
)
const nodes = paths.map(
@ -70,7 +104,8 @@ export const Intersect = () => {
const theTransforms = getTransformInfos(
{
...selectionRanges,
codeBasedSelections: selectionRanges.codeBasedSelections.slice(1),
codeBasedSelections:
_forcedSelectionRanges.codeBasedSelections.slice(1),
},
ast,
'intersect'
@ -81,7 +116,8 @@ export const Intersect = () => {
secondaryVarDecs.length === 1 &&
isAllTooltips &&
isOthersLinkedToPrimary &&
theTransforms.every(Boolean)
theTransforms.every(Boolean) &&
_forcedSelectionRanges?.codeBasedSelections?.[1]?.type === 'line-end'
setEnable(_enableEqual)
}, [guiMode, selectionRanges])
if (guiMode.mode !== 'sketch') return null
@ -89,11 +125,11 @@ export const Intersect = () => {
return (
<button
onClick={async () => {
if (transformInfos && ast) {
if (transformInfos && ast && forecdSelectionRanges) {
const { modifiedAst, tagInfo, valueUsedInTransform } =
transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)),
selectionRanges,
selectionRanges: forecdSelectionRanges,
transformInfos,
programMemory,
})
@ -129,7 +165,7 @@ export const Intersect = () => {
const { modifiedAst: _modifiedAst } =
transformSecondarySketchLinesTagFirst({
ast,
selectionRanges,
selectionRanges: forecdSelectionRanges,
transformInfos,
programMemory,
forceSegName: segName,

View File

@ -1,5 +1,5 @@
import { PathToNode, ProgramMemory } from './executor'
import { Selection } from '../useStore'
import { PathToNode, ProgramMemory, SketchGroup, SourceRange } from './executor'
import { Selection, TooTip } from '../useStore'
import {
BinaryExpression,
Program,
@ -13,6 +13,13 @@ import {
Identifier,
} from './abstractSyntaxTree'
import { createIdentifier, splitPathAtLastIndex } from './modifyAst'
import { getSketchSegmentFromSourceRange } from './std/sketchConstraints'
import { getAngle } from '../lib/utils'
import { getFirstArg } from './std/sketch'
import {
getConstraintLevelFromSourceRange,
getConstraintType,
} from './std/sketchcombos'
export function getNodeFromPath<T>(
node: Program,
@ -242,7 +249,7 @@ export function getNodePathFromSourceRange(
sourceRange: Selection['range'],
previousPath: PathToNode = [['body', '']]
): PathToNode {
const [start, end] = sourceRange
const [start, end] = sourceRange || []
let path: PathToNode = [...previousPath]
const _node = { ...node }
@ -409,3 +416,74 @@ export function isValueZero(val?: Value): boolean {
Number(val.argument.value) === 0)
)
}
export function isLinesParallelAndConstrained(
ast: Program,
programMemory: ProgramMemory,
primaryLine: Selection,
secondaryLine: Selection
): {
isParallelAndConstrained: boolean
sourceRange: SourceRange
} {
try {
const EPSILON = 0.005
const primaryPath = getNodePathFromSourceRange(ast, primaryLine.range)
const secondaryPath = getNodePathFromSourceRange(ast, secondaryLine.range)
const secondaryNode = getNodeFromPath<CallExpression>(
ast,
secondaryPath,
'CallExpression'
).node
const varDec = getNodeFromPath(ast, primaryPath, 'VariableDeclaration').node
const varName = (varDec as VariableDeclaration)?.declarations[0]?.id?.name
const path = programMemory?.root[varName] as SketchGroup
const primarySegment = getSketchSegmentFromSourceRange(
path,
primaryLine.range
).segment
const { segment: secondarySegment, index: secondaryIndex } =
getSketchSegmentFromSourceRange(path, secondaryLine.range)
const primaryAngle = getAngle(primarySegment.from, primarySegment.to)
const secondaryAngle = getAngle(secondarySegment.from, secondarySegment.to)
const secondaryAngleAlt = getAngle(
secondarySegment.to,
secondarySegment.from
)
const isParallel =
Math.abs(primaryAngle - secondaryAngle) < EPSILON ||
Math.abs(primaryAngle - secondaryAngleAlt) < EPSILON
// is secordary line fully constrain, or has constrain type of 'angle'
const secondaryFirstArg = getFirstArg(secondaryNode)
const constraintType = getConstraintType(
secondaryFirstArg.val,
secondaryNode.callee.name as TooTip
)
const constraintLevel = getConstraintLevelFromSourceRange(
secondaryLine.range,
ast
)
const isConstrained =
constraintType === 'angle' || constraintLevel === 'full'
// get the previous segment
const prevSegment = (programMemory.root[varName] as SketchGroup).value[
secondaryIndex - 1
]
const prevSourceRange = prevSegment.__geoMeta.sourceRange
const isParallelAndConstrained =
isParallel && isConstrained && !!prevSourceRange
return {
isParallelAndConstrained,
sourceRange: prevSourceRange,
}
} catch (e) {
return {
isParallelAndConstrained: false,
sourceRange: [0, 0],
}
}
}

View File

@ -1351,7 +1351,7 @@ export function addNewSketchLn({
const { from } = getSketchSegmentFromSourceRange(sketch, [
defaultLine.start,
defaultLine.end,
])
]).segment
return updateArgs({
node,
previousProgramMemory,

View File

@ -386,7 +386,7 @@ show(part001)`
const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange(
programMemory.root['part001'] as SketchGroup,
[index, index]
)
).segment
expect(segment).toEqual({
type: 'toPoint',
to: [5.62, 1.79],
@ -399,7 +399,7 @@ show(part001)`
const { __geoMeta, ...segment } = getSketchSegmentFromSourceRange(
programMemory.root['part001'] as SketchGroup,
[index, index]
)
).segment
expect(segment).toEqual({ type: 'base', to: [0, 0.04], from: [0, 0.04] })
})
})

View File

@ -11,7 +11,10 @@ import { InternalFn } from './stdTypes'
export function getSketchSegmentFromSourceRange(
sketchGroup: SketchGroup,
[rangeStart, rangeEnd]: SourceRange
): SketchGroup['value'][number] {
): {
segment: SketchGroup['value'][number]
index: number
} {
const startSourceRange = sketchGroup.start?.__geoMeta.sourceRange
if (
startSourceRange &&
@ -19,14 +22,18 @@ export function getSketchSegmentFromSourceRange(
startSourceRange[1] >= rangeEnd &&
sketchGroup.start
)
return sketchGroup.start
return { segment: sketchGroup.start, index: -1 }
const line = sketchGroup.value.find(
const lineIndex = sketchGroup.value.findIndex(
({ __geoMeta: { sourceRange } }) =>
sourceRange[0] <= rangeStart && sourceRange[1] >= rangeEnd
)
const line = sketchGroup.value[lineIndex]
if (!line) throw new Error('could not find matching line')
return line
return {
segment: line,
index: lineIndex,
}
}
export const segLen: InternalFn = (

View File

@ -1422,9 +1422,10 @@ export function transformAstSketchLines({
const sketchGroup = programMemory.root?.[varName]
if (!sketchGroup || sketchGroup.type !== 'sketchGroup')
throw new Error('not a sketch group')
const seg = getSketchSegmentFromSourceRange(sketchGroup, range)
const seg = getSketchSegmentFromSourceRange(sketchGroup, range).segment
const referencedSegment = referencedSegmentRange
? getSketchSegmentFromSourceRange(sketchGroup, referencedSegmentRange)
.segment
: sketchGroup.value.find((path) => path.name === _referencedSegmentName)
const { to, from } = seg
const { modifiedAst, valueUsedInTransform } = replaceSketchLine({