Skip to content

Commit

Permalink
feat: closed spline, dimension ref part, remove getParam, getPoint 49…
Browse files Browse the repository at this point in the history
  • Loading branch information
plantain-00 committed Nov 18, 2023
1 parent c137b16 commit 675389b
Show file tree
Hide file tree
Showing 21 changed files with 273 additions and 260 deletions.
76 changes: 18 additions & 58 deletions dev/cad-editor/model.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { evaluateExpression, Expression, parseExpression, tokenizeExpression } from 'expression-engine'
import { produce, Patch } from 'immer'
import React from 'react'
import { ArrayEditor, BooleanEditor, EnumEditor, getArrayEditorProps, NumberEditor, ObjectArrayEditor, ObjectEditor, and, boolean, breakPolylineToPolylines, EditPoint, exclusiveMinimum, GeneralFormLine, getColorString, getPointsBounding, isRecord, isSamePoint, iterateIntersectionPoints, MapCache3, minimum, Nullable, number, optional, or, Path, Pattern, Position, ReactRenderTarget, Region, Size, string, TwoPointsFormRegion, ValidationResult, Validator, WeakmapCache, WeakmapCache2, record, StringEditor, MapCache, getArrow, isZero, getTwoPointsDistance, getPointByLengthAndDirection, SnapTarget as CoreSnapTarget, mergePolylinesToPolyline, getTwoLineSegmentsIntersectionPoint, deduplicatePosition, iteratePolylineLines, zoomToFitPoints, JsonEditorProps, useUndoRedo, useFlowLayoutTextEditor, controlStyle, reactCanvasRenderTarget, metaKeyIfMacElseCtrlKey, Align, VerticalAlign, TextStyle, aligns, verticalAligns, rotatePosition, m3, GeometryLine, getPointAndGeometryLineMinimumDistance, getAngleInRange, getTwoPointsRadian, radianToAngle, getArcPointAtAngle, getEllipseAngle, getEllipseArcPointAtAngle, getQuadraticCurvePointAtPercent, getQuadraticCurvePercentAtPoint, getBezierCurvePercentAtPoint, getBezierCurvePointAtPercent, breakGeometryLines, geometryLineToPathCommands, getNurbsCurveParamAtPoint, getNurbsCurvePointAtParam, getNurbsMaxParam } from '../../src'
import { ArrayEditor, BooleanEditor, EnumEditor, getArrayEditorProps, NumberEditor, ObjectArrayEditor, ObjectEditor, and, boolean, breakPolylineToPolylines, EditPoint, exclusiveMinimum, GeneralFormLine, getColorString, getPointsBounding, isRecord, isSamePoint, iterateIntersectionPoints, MapCache3, minimum, Nullable, number, optional, or, Path, Pattern, Position, ReactRenderTarget, Region, Size, string, TwoPointsFormRegion, ValidationResult, Validator, WeakmapCache, WeakmapCache2, record, StringEditor, MapCache, getArrow, isZero, SnapTarget as CoreSnapTarget, mergePolylinesToPolyline, getTwoLineSegmentsIntersectionPoint, deduplicatePosition, iteratePolylineLines, zoomToFitPoints, JsonEditorProps, useUndoRedo, useFlowLayoutTextEditor, controlStyle, reactCanvasRenderTarget, metaKeyIfMacElseCtrlKey, Align, VerticalAlign, TextStyle, aligns, verticalAligns, rotatePosition, m3, GeometryLine, getPointAndGeometryLineMinimumDistance, breakGeometryLines, geometryLineToPathCommands, getGeometryLinesPointAtParam } from '../../src'
import type { LineContent } from './plugins/line-polyline.plugin'
import type { TextContent } from './plugins/text.plugin'
import type { ArcContent } from './plugins/circle-arc.plugin'
Expand Down Expand Up @@ -148,6 +148,7 @@ export const variableValuesModel = {
export const containerModel = {
...variableValuesModel,
isContainer: true,
canSelectPart: true,
}

export const arrowModel = {
Expand Down Expand Up @@ -216,8 +217,6 @@ export type Model<T> = Partial<FeatureModels> & {
isPointIn?(content: T, point: Position): boolean
getStartPoint?(content: T): Position
getEndPoint?(content: T): Position
getParam?(content: T, point: Position): number
getPoint?(content: T, param: number): Position
getChildByPoint?(content: T, point: Position, options: { textStyleId?: number }): { child: number[], patches?: [Patch[], Patch[]] } | undefined
getArea?(content: T): number
reverse?(content: T): T
Expand Down Expand Up @@ -1298,57 +1297,6 @@ export function getViewportByRegion(content: BaseContent, contentsBounding: TwoP
}
}

export function getLinesParamAtPoint(point: Position, lines: GeometryLine[]) {
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
if (isZero(getPointAndGeometryLineMinimumDistance(point, line), 1e-4)) {
if (Array.isArray(line)) {
return i + getTwoPointsDistance(line[0], point) / getTwoPointsDistance(...line)
}
if (line.type === 'arc') {
const angle = getAngleInRange(radianToAngle(getTwoPointsRadian(point, line.curve)), line.curve)
return i + (angle - line.curve.startAngle) / (line.curve.endAngle - line.curve.startAngle)
}
if (line.type === 'ellipse arc') {
const angle = getAngleInRange(getEllipseAngle(point, line.curve), line.curve)
return i + (angle - line.curve.startAngle) / (line.curve.endAngle - line.curve.startAngle)
}
if (line.type === 'quadratic curve') {
return i + getQuadraticCurvePercentAtPoint(line.curve, point)
}
if (line.type === 'bezier curve') {
return i + getBezierCurvePercentAtPoint(line.curve, point)
}
if (line.type === 'nurbs curve') {
return i + getNurbsCurveParamAtPoint(line.curve, point) / getNurbsMaxParam(line.curve)
}
}
}
return 0
}

export function getLinesPointAtParam(param: number, lines: GeometryLine[]) {
const index = Math.floor(param)
const line = lines[index]
if (Array.isArray(line)) {
const distance = (param - index) * getTwoPointsDistance(...line)
return getPointByLengthAndDirection(line[0], distance, line[1])
}
if (line.type === 'arc') {
return getArcPointAtAngle(line.curve, (param - index) * (line.curve.endAngle - line.curve.startAngle) + line.curve.startAngle)
}
if (line.type === 'ellipse arc') {
return getEllipseArcPointAtAngle(line.curve, (param - index) * (line.curve.endAngle - line.curve.startAngle) + line.curve.startAngle)
}
if (line.type === 'quadratic curve') {
return getQuadraticCurvePointAtPercent(line.curve.from, line.curve.cp, line.curve.to, param)
}
if (line.type === 'bezier curve') {
return getBezierCurvePointAtPercent(line.curve.from, line.curve.cp1, line.curve.cp2, line.curve.to, param)
}
return getNurbsCurvePointAtParam(line.curve, param * getNurbsMaxParam(line.curve))
}

export interface PositionRef {
id: number | BaseContent
snapIndex: number
Expand All @@ -1368,7 +1316,10 @@ export function getRefPosition(positionRef: PositionRef | undefined, contents: r
const model = getContentModel(ref)
let p: Position | undefined = model?.getSnapPoints?.(ref, contents)?.[positionRef.snapIndex]
if (!p && positionRef.param !== undefined) {
p = model?.getPoint?.(ref, positionRef.param)
const lines = model?.getGeometries?.(ref, contents).lines
if (lines) {
p = getGeometryLinesPointAtParam(positionRef.param, lines)
}
}
return p
}
Expand All @@ -1386,18 +1337,27 @@ export const PartRef = {
partIndex: optional(number),
}

export function getRefPart(partRef: PartRef | undefined, contents: readonly Nullable<BaseContent>[]) {
export function getRefPart<T extends BaseContent>(
partRef: PartRef | undefined,
contents: readonly Nullable<BaseContent>[],
filter: (content: BaseContent) => content is T = (c): c is T => true,
) {
if (partRef !== undefined) {
const ref = getReference(partRef.id, contents)
if (ref) {
const model = getContentModel(ref)
if (partRef.partIndex !== undefined) {
const line = model?.getGeometries?.(ref, contents)?.lines?.[partRef.partIndex]
if (line) {
return geometryLineToContent(line)
const content = geometryLineToContent(line)
if (content && filter(content)) {
return content
}
}
}
return ref
if (filter(ref)) {
return ref
}
}
}
return
Expand Down
6 changes: 3 additions & 3 deletions dev/cad-editor/plugins/center-line.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export function getModel(ctx: PluginContext): model.Model<CenterLineReferenceCon
ref2: ctx.PartRef,
})
function getCenterLineGeometriesFromCache(content: Omit<CenterLineReferenceContent, "type">, contents: readonly core.Nullable<model.BaseContent>[]) {
const ref1 = ctx.getRefPart(content.ref1, contents)
const ref2 = ctx.getRefPart(content.ref2, contents)
if (ref1 && ref2 && isLineContent(ref1) && isLineContent(ref2)) {
const ref1 = ctx.getRefPart(content.ref1, contents, isLineContent)
const ref2 = ctx.getRefPart(content.ref2, contents, isLineContent)
if (ref1 && ref2) {
return centerMarkLinesCache.get(ref1, ref2, content, () => {
const line = ctx.maxmiumBy([
[ctx.getTwoPointCenter(ref1.points[0], ref2.points[0]), ctx.getTwoPointCenter(ref1.points[1], ref2.points[1])] as [core.Position, core.Position],
Expand Down
42 changes: 22 additions & 20 deletions dev/cad-editor/plugins/center-mark.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import type * as model from '../model'
import { ArcContent, CircleContent, isArcContent, isCircleContent } from './circle-arc.plugin'

export type CenterMarkReferenceContent = model.BaseContent<'center mark'> & {
refId: number | model.BaseContent
ref: model.PartRef
}

export function getModel(ctx: PluginContext): model.Model<CenterMarkReferenceContent> {
const CenterMarkReferenceContent = ctx.and(ctx.BaseContent('center mark'), {
refId: ctx.or(ctx.number, ctx.Content)
ref: ctx.PartRef,
})
function getCenterMarkGeometriesFromCache(content: Omit<CenterMarkReferenceContent, "type">, contents: readonly core.Nullable<model.BaseContent>[]) {
const target = ctx.getReference(content.refId, contents, contentSelectable)
const target = ctx.getRefPart(content.ref, contents, contentSelectable)
if (target) {
return centerMarkLinesCache.get(target, content, () => {
const lines: [core.Position, core.Position][] = [
Expand Down Expand Up @@ -41,18 +41,22 @@ export function getModel(ctx: PluginContext): model.Model<CenterMarkReferenceCon
},
getGeometries: getCenterMarkGeometriesFromCache,
canSelectPart: true,
propertyPanel(content, update, contents, { acquireContent }) {
propertyPanel(content, update) {
return {
refId: typeof content.refId === 'number' ? <ctx.NumberEditor value={content.refId} setValue={(v) => update(c => { if (isCenterMarkContent(c)) { c.refId = v } })} /> : [],
refIdFrom: typeof content.refId === 'number' ? <ctx.Button onClick={() => acquireContent({ count: 1, selectable: (i) => contentSelectable(contents[i[0]]) }, p => update(c => { if (isCenterMarkContent(c)) { c.refId = p[0][0] } }))}>canvas</ctx.Button> : [],
ref: [
typeof content.ref.id === 'number' ? <ctx.NumberEditor value={content.ref.id} setValue={(v) => update(c => { if (isCenterMarkContent(c)) { c.ref.id = v } })} /> : undefined,
content.ref.partIndex !== undefined ? <ctx.NumberEditor value={content.ref.partIndex} setValue={(v) => update(c => { if (isCenterMarkContent(c)) { c.ref.partIndex = v } })} /> : undefined,
],
}
},
isValid: (c, p) => ctx.validate(c, CenterMarkReferenceContent, p),
getRefIds: (content) => typeof content.refId === 'number' ? [content.refId] : [],
getRefIds: (content) => typeof content.ref === 'number' ? [content.ref] : [],
updateRefId(content, update) {
const newRefId = update(content.refId)
if (newRefId !== undefined) {
content.refId = newRefId
if (content.ref) {
const newRefId = update(content.ref.id)
if (newRefId !== undefined) {
content.ref.id = newRefId
}
}
},
}
Expand All @@ -79,17 +83,15 @@ export function getCommand(ctx: PluginContext): Command {
name: 'create center mark',
icon,
contentSelectable,
selectType: 'select part',
execute({ contents, selected }) {
const newContents: CenterMarkReferenceContent[] = []
contents.forEach((content, index) => {
if (content && ctx.isSelected([index], selected) && (this.contentSelectable?.(content, contents) ?? true)) {
newContents.push({
type: 'center mark',
refId: index,
})
}
})
contents.push(...newContents)
contents.push(...selected.map(([index, partIndex]) => ({
type: 'center mark',
ref: {
id: index,
partIndex,
},
})))
},
}
}
6 changes: 1 addition & 5 deletions dev/cad-editor/plugins/circle-arc.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,6 @@ export function getModel(ctx: PluginContext) {
getRefIds: ctx.getStrokeAndFillRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
isPointIn: (content, point) => ctx.getTwoPointsDistance(content, point) < content.r,
getParam: (content, point) => ctx.getCircleRadian(point, content),
getPoint: (content, param) => ctx.getCirclePointAtRadian(content, param),
getArea: (content) => Math.PI * content.r ** 2,
} as model.Model<CircleContent>,
{
Expand Down Expand Up @@ -313,7 +311,7 @@ export function getModel(ctx: PluginContext) {
return target.renderArc(content.x, content.y, content.r, content.startAngle, content.endAngle, { ...options, counterclockwise: content.counterclockwise })
},
renderIfSelected(content, { color, target, strokeWidth }) {
const { points } = getArcGeometries({ ...content, startAngle: content.endAngle, endAngle: content.startAngle + 360 })
const { points } = getArcGeometries({ ...content, startAngle: content.endAngle, endAngle: content.startAngle })
return target.renderPolyline(points, { strokeColor: color, dashArray: [4], strokeWidth })
},
getOperatorRenderPosition(content) {
Expand Down Expand Up @@ -412,8 +410,6 @@ export function getModel(ctx: PluginContext) {
updateRefId: ctx.updateStrokeAndFillRefIds,
getStartPoint: (content) => ctx.getArcPointAtAngle(content, content.startAngle),
getEndPoint: (content) => ctx.getArcPointAtAngle(content, content.endAngle),
getParam: (content, point) => ctx.getCircleRadian(point, content),
getPoint: (content, param) => ctx.getCirclePointAtRadian(content, param),
getArea: (content) => {
const radian = ctx.angleToRadian(content.endAngle - content.startAngle)
return content.r ** 2 * (radian - Math.sin(radian)) / 2
Expand Down
2 changes: 0 additions & 2 deletions dev/cad-editor/plugins/diamond.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@ export function getModel(ctx: PluginContext): model.Model<DiamondContent> {
getRefIds: ctx.getStrokeAndFillRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
isPointIn: (content, point) => ctx.pointInPolygon(point, getGeometries(content).points),
getParam: (content, point) => ctx.getLinesParamAtPoint(point, getGeometries(content).lines),
getPoint: (content, param) => ctx.getLinesPointAtParam(param, getGeometries(content).lines),
}
}

Expand Down
6 changes: 1 addition & 5 deletions dev/cad-editor/plugins/ellipse.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,6 @@ export function getModel(ctx: PluginContext) {
getRefIds: ctx.getStrokeAndFillRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
isPointIn: (content, point) => ctx.pointInPolygon(point, getEllipseGeometries(content).points),
getParam: (content, point) => ctx.getEllipseAngle(point, content),
getPoint: (content, param) => ctx.getEllipsePointAtRadian(content, ctx.angleToRadian(param)),
getArea: (content) => Math.PI * content.rx * content.ry,
}
return [
Expand Down Expand Up @@ -303,7 +301,7 @@ export function getModel(ctx: PluginContext) {
return target.renderPolyline(points, options)
},
renderIfSelected(content, { color, target, strokeWidth }) {
const { points } = getEllipseArcGeometries({ ...content, startAngle: content.endAngle, endAngle: content.startAngle + 360 })
const { points } = getEllipseArcGeometries({ ...content, startAngle: content.endAngle, endAngle: content.startAngle })
return target.renderPolyline(points, { strokeColor: color, dashArray: [4], strokeWidth })
},
getOperatorRenderPosition(content) {
Expand Down Expand Up @@ -394,8 +392,6 @@ export function getModel(ctx: PluginContext) {
updateRefId: ctx.updateStrokeAndFillRefIds,
getStartPoint: (content) => ctx.getEllipseArcPointAtAngle(content, content.startAngle),
getEndPoint: (content) => ctx.getEllipseArcPointAtAngle(content, content.endAngle),
getParam: (content, point) => ctx.getEllipseAngle(point, content),
getPoint: (content, param) => ctx.getEllipsePointAtRadian(content, ctx.angleToRadian(param)),
getArea: (content) => {
const radian = ctx.angleToRadian(content.endAngle - content.startAngle)
return content.rx * content.ry * (radian - Math.sin(radian)) / 2
Expand Down
2 changes: 0 additions & 2 deletions dev/cad-editor/plugins/line-polyline.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ export function getModel(ctx: PluginContext) {
updateRefId: ctx.updateStrokeAndFillRefIds,
getStartPoint: (content) => content.points[0],
getEndPoint: (content) => content.points[content.points.length - 1],
getParam: (content, point) => ctx.getLinesParamAtPoint(point, getPolylineGeometries(content).lines),
getPoint: (content, param) => ctx.getLinesPointAtParam(param, getPolylineGeometries(content).lines),
reverse: (content) => ({
...content,
points: content.points.slice().reverse(),
Expand Down
9 changes: 5 additions & 4 deletions dev/cad-editor/plugins/linear-dimension.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export function getModel(ctx: PluginContext): model.Model<LinearDimensionContent
},
getEditPoints(content, contents) {
return ctx.getEditPointsFromCache(content, () => {
const { p1, p2 } = getLinearDimensionPositions(content, contents)
return {
editPoints: [
{
Expand All @@ -99,8 +100,8 @@ export function getModel(ctx: PluginContext): model.Model<LinearDimensionContent
},
},
{
x: content.p1.x,
y: content.p1.y,
x: p1.x,
y: p1.y,
cursor: 'move',
update(c, { cursor, start, scale, target }) {
if (!isLinearDimensionContent(c)) {
Expand All @@ -113,8 +114,8 @@ export function getModel(ctx: PluginContext): model.Model<LinearDimensionContent
},
},
{
x: content.p2.x,
y: content.p2.y,
x: p2.x,
y: p2.y,
cursor: 'move',
update(c, { cursor, start, scale, target }) {
if (!isLinearDimensionContent(c)) {
Expand Down
2 changes: 0 additions & 2 deletions dev/cad-editor/plugins/nurbs.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ export function getModel(ctx: PluginContext): model.Model<NurbsContent>[] {
const lines = getNurbsGeometries(content).lines
return ctx.getGeometryLineStartAndEnd(lines[lines.length - 1]).end
},
getParam: (content, point) => ctx.getLinesParamAtPoint(point, getNurbsGeometries(content).lines),
getPoint: (content, param) => ctx.getLinesPointAtParam(param, getNurbsGeometries(content).lines),
reverse: (content) => ctx.reverseNurbs(content),
}
return [
Expand Down
2 changes: 0 additions & 2 deletions dev/cad-editor/plugins/polygon.plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,6 @@ export function getModel(ctx: PluginContext): model.Model<PolygonContent> {
getRefIds: ctx.getStrokeAndFillRefIds,
updateRefId: ctx.updateStrokeAndFillRefIds,
isPointIn: (content, point) => ctx.pointInPolygon(point, content.points),
getParam: (content, point) => ctx.getLinesParamAtPoint(point, getPolygonGeometries(content).lines),
getPoint: (content, param) => ctx.getLinesPointAtParam(param, getPolygonGeometries(content).lines),
}
}

Expand Down
Loading

0 comments on commit 675389b

Please sign in to comment.