Skip to content

Commit

Permalink
feat: removeRefIds 654993b
Browse files Browse the repository at this point in the history
  • Loading branch information
plantain-00 committed Mar 28, 2024
1 parent 6fef0b4 commit b7fdfd7
Show file tree
Hide file tree
Showing 47 changed files with 415 additions and 253 deletions.
2 changes: 1 addition & 1 deletion dev/cad-editor/command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export function useCommands(
if (!model) return c
const refIds = model.getRefIds?.(c)
if (!refIds) return c
if (refIds.every(d => typeof d !== 'number' || idMap[d] === undefined)) return c
if (refIds.every(d => !d || typeof d.id !== 'number' || idMap[d.id] === undefined)) return c
return produce(c, draft => {
model.updateRefId?.(draft, d => typeof d === 'number' ? idMap[d] : undefined)
})
Expand Down
99 changes: 82 additions & 17 deletions dev/cad-editor/model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,9 @@ export type Model<T> = Partial<FeatureModels> & {
transformPosition: (p: Position) => Position,
activeChild?: number[],
): JSX.Element
getRefIds?(content: T): Nullable<ContentRef>[] | undefined
getRefIds?(content: T): Nullable<RefId>[] | undefined
updateRefId?(content: T, update: (id: ContentRef) => ContentRef | undefined): void
deleteRefId?(content: T, ids: ContentRef[]): void
isValid(content: Omit<T, 'type'>, path?: Path): ValidationResult
getVariableNames?(content: Omit<T, 'type'>): string[]
isPointIn?(content: T, point: Position, contents: readonly Nullable<BaseContent>[]): boolean
Expand Down Expand Up @@ -1050,18 +1051,15 @@ export function getReference<T extends BaseContent>(
return
}

export function contentIsReferenced(content: object, contents: readonly Nullable<BaseContent>[]): boolean {
export function contentIsDeletable(content: BaseContent, contents: readonly Nullable<BaseContent>[]): boolean {
if (content.readonly) return false
const id = getContentIndex(content, contents)
for (const content of iterateAllContents(contents)) {
if (getContentModel(content)?.getRefIds?.(content)?.includes(id)) {
return true
if (getContentModel(content)?.getRefIds?.(content)?.some(d => d?.id === id && d.required)) {
return false
}
}
return false
}

export function contentIsDeletable(content: BaseContent, contents: readonly Nullable<BaseContent>[]): boolean {
return !content.readonly && !contentIsReferenced(content, contents)
return true
}
export function contentIsClosedPath(content: Nullable<BaseContent>) {
return !!content && !content.readonly && getContentModel(content)?.isPointIn !== undefined
Expand All @@ -1080,13 +1078,13 @@ export function* iterateRefIds(ids: Nullable<ContentRef>[] | undefined, contents
const content = typeof id !== 'number' ? id : contents[id]
if (content) {
const refIds = getContentModel(content)?.getRefIds?.(content)
yield* iterateRefIds(refIds, contents)
yield* iterateRefIds(refIds?.map(d => d?.id), contents)
}
}
}

export function* iterateRefContents(
ids: Nullable<ContentRef>[] | undefined,
ids: Nullable<RefId>[] | undefined,
contents: readonly Nullable<BaseContent>[],
parents: Omit<BaseContent, 'type'>[],
): Generator<BaseContent, void, unknown> {
Expand All @@ -1096,7 +1094,7 @@ export function* iterateRefContents(
for (const id of ids) {
if (id === undefined) continue
if (id === null) continue
const content = typeof id !== 'number' ? id : contents[id]
const content = typeof id.id !== 'number' ? id.id : contents[id.id]
if (content && !parents.includes(content)) {
yield content
const refIds = getContentModel(content)?.getRefIds?.(content)
Expand All @@ -1105,6 +1103,17 @@ export function* iterateRefContents(
}
}

export function deleteSelectedContents(contents: Nullable<BaseContent>[], indexes: number[]) {
for (const index of indexes) {
contents[index] = undefined
}
contents.forEach((content, index) => {
if (content && !indexes.includes(index)) {
getContentModel(content)?.deleteRefId?.(content, indexes)
}
})
}

export function updateReferencedContents(
content: BaseContent,
newContent: BaseContent,
Expand All @@ -1116,7 +1125,7 @@ export function updateReferencedContents(
for (const c of iterateAllContents(contents)) {
if (selected?.includes(c)) continue
const model = getContentModel(c)
if (model?.getRefIds?.(c)?.includes(id)) {
if (model?.getRefIds?.(c)?.some(d => d?.id === id)) {
assistentContents.push(produce(c, (draft) => {
model.updateRefId?.(draft, d => {
if (d === id) {
Expand Down Expand Up @@ -1209,7 +1218,7 @@ export function renderContainerIfSelected<V, T extends ContainerFields>(
container: T,
ctx: RenderIfSelectedContext<V>,
parents: Omit<BaseContent, 'type'>[],
getRefIds: (content: T) => Nullable<ContentRef>[],
getRefIds: (content: T) => Nullable<RefId>[],
) {
const { bounding } = getContainerGeometries<T>(container, ctx.contents, getRefIds, parents)
if (!bounding) {
Expand All @@ -1227,7 +1236,7 @@ export function renderContainerIfSelected<V, T extends ContainerFields>(
export function getContainerGeometries<T extends ContainerFields>(
content: T,
contents: readonly Nullable<BaseContent>[],
getRefIds: (content: T) => Nullable<ContentRef>[],
getRefIds: (content: T) => Nullable<RefId>[],
parents: Omit<BaseContent, 'type'>[],
) {
return getContentsGeometries<T>(content, contents, getRefIds, parents)
Expand All @@ -1236,7 +1245,7 @@ export function getContainerGeometries<T extends ContainerFields>(
export function getContentsGeometries<T extends ContainerFields>(
content: T,
contents: readonly Nullable<BaseContent>[],
getRefIds: (content: T) => Nullable<ContentRef>[],
getRefIds: (content: T) => Nullable<RefId>[],
parents: Omit<BaseContent, 'type'>[],
getAllContents = (c: T) => c.contents,
) {
Expand Down Expand Up @@ -1345,7 +1354,7 @@ export function getContainerRenderIfSelected<V, T extends ContainerFields>(
content: T,
ctx: RenderIfSelectedContext<V>,
parents: Omit<BaseContent, 'type'>[],
getRefIds: (content: T) => Nullable<ContentRef>[]
getRefIds: (content: T) => Nullable<RefId>[]
) {
return renderContainerIfSelected(content, ctx, parents, getRefIds)
}
Expand All @@ -1372,6 +1381,57 @@ export function getContentsBreak(array: Nullable<BaseContent>[], points: Positio
return result
}

export function toRefId(id?: ContentRef, required?: boolean): RefId[] {
return id !== undefined ? [{ id, required }] : []
}

export function toRefIds(ids?: Nullable<ContentRef>[], required?: boolean): RefId[] {
const result: RefId[] = []
if (ids) {
for (const id of ids) {
if (id) {
result.push({ id, required })
}
}
}
return result
}

export function getStrokeRefIds(content: StrokeFields): RefId[] {
return toRefId(content.strokeStyleId)
}

export function getFillRefIds(content: FillFields): RefId[] {
return toRefId(content.fillStyleId)
}

export function getStrokeAndFillRefIds(content: StrokeFields & FillFields): RefId[] {
return [...toRefId(content.strokeStyleId), ...toRefId(content.fillStyleId)]
}

export function deleteStrokeRefIds(content: StrokeFields, ids: ContentRef[]) {
if (content.strokeStyleId !== undefined && ids.includes(content.strokeStyleId)) {
content.strokeStyleId = undefined
}
}

export function deleteFillRefIds(content: FillFields, ids: ContentRef[]) {
if (content.fillStyleId !== undefined && ids.includes(content.fillStyleId)) {
content.fillStyleId = undefined
}
}

export function deleteStrokeAndFillRefIds(content: StrokeFields & FillFields, ids: ContentRef[]) {
deleteStrokeRefIds(content, ids)
deleteFillRefIds(content, ids)
}

export function deleteTextStyleRefIds(content: TextFields, ids: ContentRef[]) {
if (content.textStyleId !== undefined && ids.includes(content.textStyleId)) {
content.textStyleId = undefined
}
}

export function updateStrokeRefIds(content: StrokeFields, update: (id: ContentRef) => ContentRef | undefined) {
if (content.strokeStyleId !== undefined) {
const newRefId = update(content.strokeStyleId)
Expand Down Expand Up @@ -1524,6 +1584,11 @@ export function getViewportByRegion(content: BaseContent, contentsBounding: TwoP
}
}

export interface RefId {
id: ContentRef
required?: boolean
}

export type ContentRef = number | BaseContent

export const ContentRef = or(number, Content)
Expand Down
11 changes: 10 additions & 1 deletion dev/cad-editor/plugins/arrow.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function getModel(ctx: PluginContext): model.Model<ArrowContent> {
ref1: ctx.optional(ctx.PositionRef),
ref2: ctx.optional(ctx.PositionRef),
})
const getRefIds = (content: ArrowContent) => [content.strokeStyleId, content.ref1?.id, content.ref2?.id]
const getRefIds = (content: ArrowContent): model.RefId[] => [...ctx.getStrokeRefIds(content), ...ctx.toRefIds([content.ref1?.id, content.ref2?.id])]
function getArrowGeometriesFromCache(content: ArrowContent, contents: readonly core.Nullable<model.BaseContent>[]) {
const refs = new Set(ctx.iterateRefContents(getRefIds(content), contents, [content]))
return ctx.getGeometriesFromCache(content, refs, () => {
Expand Down Expand Up @@ -164,6 +164,15 @@ export function getModel(ctx: PluginContext): model.Model<ArrowContent> {
}
ctx.updateStrokeRefIds(content, update)
},
deleteRefId(content, ids) {
if (content.ref1 && ids.includes(content.ref1.id)) {
content.ref1 = undefined
}
if (content.ref2 && ids.includes(content.ref2.id)) {
content.ref2 = undefined
}
ctx.deleteStrokeRefIds(content, ids)
},
reverse: (content) => ({
...content,
p1: content.p2,
Expand Down
10 changes: 3 additions & 7 deletions dev/cad-editor/plugins/block.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export function getModel(ctx: PluginContext): (model.Model<BlockContent> | model
angle: ctx.number,
scale: ctx.optional(ctx.or(ctx.number, ctx.Position)),
})
const getBlockRefIds = (content: Omit<BlockContent, 'type'>) => content.contents
const getBlockReferenceRefIds = (content: BlockReferenceContent) => [content.refId]
const getBlockRefIds = (content: Omit<BlockContent, 'type'>): model.RefId[] => ctx.toRefIds(content.contents)
const getBlockReferenceRefIds = (content: BlockReferenceContent): model.RefId[] => ctx.toRefId(content.refId, true)
const blockModel: model.Model<BlockContent> = {
type: 'block',
...ctx.containerModel,
Expand Down Expand Up @@ -349,11 +349,7 @@ export function getCommand(ctx: PluginContext): Command[] {
contents: contents.filter((c, i) => c && ctx.isSelected([i], selected) && contentSelectable(c, contents)),
base: p,
}
contents.forEach((_, i) => {
if (ctx.isSelected([i], selected)) {
contents[i] = undefined
}
})
ctx.deleteSelectedContents(contents, selected.map(s => s[0]))
contents.push(newContent)
}
})
Expand Down
4 changes: 1 addition & 3 deletions dev/cad-editor/plugins/break.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ export function getCommand(ctx: PluginContext): Command {
}
}
})
for (const index of indexes) {
contents[index] = undefined
}
ctx.deleteSelectedContents(contents, indexes)
contents.push(...newContents)
},
contentSelectable(content, contents) {
Expand Down
18 changes: 7 additions & 11 deletions dev/cad-editor/plugins/center-line.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function getModel(ctx: PluginContext): model.Model<CenterLineReferenceCon
ref1: ctx.PartRef,
ref2: ctx.PartRef,
})
const getRefIds = (content: CenterLineReferenceContent) => [content.ref1.id, content.ref2.id]
const getRefIds = (content: CenterLineReferenceContent): model.RefId[] => ctx.toRefIds([content.ref1.id, content.ref2.id], true)
function getCenterLineGeometriesFromCache(content: CenterLineReferenceContent, contents: readonly core.Nullable<model.BaseContent>[]) {
const refs = new Set(ctx.iterateRefContents(getRefIds(content), contents, [content]))
return ctx.getGeometriesFromCache(content, refs, () => {
Expand Down Expand Up @@ -60,17 +60,13 @@ export function getModel(ctx: PluginContext): model.Model<CenterLineReferenceCon
isValid: (c, p) => ctx.validate(c, CenterLineReferenceContent, p),
getRefIds,
updateRefId(content, update) {
if (content.ref1) {
const newRefId = update(content.ref1.id)
if (newRefId !== undefined) {
content.ref1.id = newRefId
}
const newRefId1 = update(content.ref1.id)
if (newRefId1 !== undefined) {
content.ref1.id = newRefId1
}
if (content.ref2) {
const newRefId = update(content.ref2.id)
if (newRefId !== undefined) {
content.ref2.id = newRefId
}
const newRefId2 = update(content.ref2.id)
if (newRefId2 !== undefined) {
content.ref2.id = newRefId2
}
},
}
Expand Down
10 changes: 4 additions & 6 deletions dev/cad-editor/plugins/center-mark.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function getModel(ctx: PluginContext): model.Model<CenterMarkReferenceCon
const CenterMarkReferenceContent = ctx.and(ctx.BaseContent('center mark'), {
ref: ctx.PartRef,
})
const getRefIds = (content: CenterMarkReferenceContent) => [content.ref.id]
const getRefIds = (content: CenterMarkReferenceContent): model.RefId[] => ctx.toRefId(content.ref.id, true)
function getCenterMarkGeometriesFromCache(content: CenterMarkReferenceContent, contents: readonly core.Nullable<model.BaseContent>[]) {
const refs = new Set(ctx.iterateRefContents(getRefIds(content), contents, [content]))
return ctx.getGeometriesFromCache(content, refs, () => {
Expand Down Expand Up @@ -53,11 +53,9 @@ export function getModel(ctx: PluginContext): model.Model<CenterMarkReferenceCon
isValid: (c, p) => ctx.validate(c, CenterMarkReferenceContent, p),
getRefIds,
updateRefId(content, update) {
if (content.ref) {
const newRefId = update(content.ref.id)
if (newRefId !== undefined) {
content.ref.id = newRefId
}
const newRefId = update(content.ref.id)
if (newRefId !== undefined) {
content.ref.id = newRefId
}
},
}
Expand Down
4 changes: 3 additions & 1 deletion dev/cad-editor/plugins/circle-arc.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function getModel(ctx: PluginContext) {
rExpression: ctx.optional(ctx.string),
})
const ArcContent = ctx.and(ctx.BaseContent('arc'), ctx.StrokeFields, ctx.FillFields, ctx.AngleDeltaFields, ctx.Arc)
const getRefIds = (content: model.StrokeFields & model.FillFields) => [content.strokeStyleId, content.fillStyleId]
const getRefIds = (content: model.StrokeFields & model.FillFields): model.RefId[] => ctx.getStrokeAndFillRefIds(content)
const circleGeometriesCache = new ctx.WeakmapValuesCache<Omit<CircleContent, "type">, model.BaseContent, model.Geometries<{ points: core.Position[], quadrantPoints: core.Position[] }>>()
const arcGeometriesCache = new ctx.WeakmapValuesCache<Omit<ArcContent, "type">, model.BaseContent, model.Geometries<{ points: core.Position[], start: core.Position, end: core.Position, middle: core.Position }>>()
function getCircleGeometries(content: Omit<CircleContent, "type">, contents: readonly core.Nullable<model.BaseContent>[], time?: number) {
Expand Down Expand Up @@ -230,6 +230,7 @@ export function getModel(ctx: PluginContext) {
isValid: (c, p) => ctx.validate(c, CircleContent, p),
getRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
deleteRefId: ctx.deleteStrokeAndFillRefIds,
isPointIn: (content, point) => ctx.getTwoPointsDistance(content, point) < content.r,
getArea: (content) => Math.PI * content.r ** 2,
} as model.Model<CircleContent>,
Expand Down Expand Up @@ -447,6 +448,7 @@ export function getModel(ctx: PluginContext) {
isValid: (c, p) => ctx.validate(c, ArcContent, p),
getRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
deleteRefId: ctx.deleteStrokeAndFillRefIds,
getArea: (content) => {
const radian = ctx.angleToRadian(content.endAngle - content.startAngle)
return content.r ** 2 * (radian - Math.sin(radian)) / 2
Expand Down
9 changes: 3 additions & 6 deletions dev/cad-editor/plugins/combined-path.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type CombinedPathContent = model.BaseContent<'combined path'> & model.Con

export function getModel(ctx: PluginContext): model.Model<CombinedPathContent> {
const CombinedPathContent = ctx.and(ctx.BaseContent('combined path'), ctx.ContainerFields, ctx.StrokeFields, ctx.FillFields)
const getRefIds = (content: Omit<CombinedPathContent, 'type'>) => [content.strokeStyleId, content.fillStyleId]
const getRefIds = (content: Omit<CombinedPathContent, 'type'>): model.RefId[] => ctx.getStrokeAndFillRefIds(content)
const getGeometries = (content: CombinedPathContent, contents: readonly core.Nullable<model.BaseContent>[]) => {
const refs = new Set(ctx.iterateRefContents(getRefIds(content), contents, [content]))
return ctx.getGeometriesFromCache(content, refs, () => {
Expand Down Expand Up @@ -79,6 +79,7 @@ export function getModel(ctx: PluginContext): model.Model<CombinedPathContent> {
isValid: (c, p) => ctx.validate(c, CombinedPathContent, p),
getRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
deleteRefId: ctx.deleteStrokeAndFillRefIds,
}
}

Expand All @@ -102,11 +103,7 @@ export function getCommand(ctx: PluginContext): Command {
fillStyleId,
contents: contents.filter((c, i) => c && ctx.isSelected([i], selected) && contentSelectable(c, contents)),
}
for (let i = contents.length; i >= 0; i--) {
if (ctx.isSelected([i], selected)) {
contents[i] = undefined
}
}
ctx.deleteSelectedContents(contents, selected.map(s => s[0]))
contents.push(newContent)
},
contentSelectable,
Expand Down
3 changes: 2 additions & 1 deletion dev/cad-editor/plugins/coordinate-axis.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function getModel(ctx: PluginContext): model.Model<CoordinateAxisContent>
const CoordinateAxisContent = ctx.and(ctx.BaseContent('coordinate axis'), ctx.StrokeFields, ctx.ArrowFields, ctx.Position, ctx.Bounding, {
flipY: ctx.optional(ctx.boolean),
})
const getRefIds = (content: Omit<CoordinateAxisContent, "type">) => [content.strokeStyleId]
const getRefIds = (content: Omit<CoordinateAxisContent, "type">): model.RefId[] => ctx.getStrokeRefIds(content)
function getGeometriesFromCache(content: Omit<CoordinateAxisContent, "type">, contents: readonly core.Nullable<model.BaseContent>[]) {
const refs = new Set(ctx.iterateRefContents(getRefIds(content), contents, [content]))
return ctx.getGeometriesFromCache(content, refs, () => {
Expand Down Expand Up @@ -119,6 +119,7 @@ export function getModel(ctx: PluginContext): model.Model<CoordinateAxisContent>
isValid: (c, p) => ctx.validate(c, CoordinateAxisContent, p),
getRefIds,
updateRefId: ctx.updateStrokeRefIds,
deleteRefId: ctx.deleteStrokeRefIds,
}
}

Expand Down
Loading

0 comments on commit b7fdfd7

Please sign in to comment.