replicad
replicad copied to clipboard
Convert Entities Function
I have a lot of workflows in traditional CAD applications that make use of a "Convert Entities" function to turn a loop of edges back into a sketch for downstream use. Is this something that can be natively supported? I tried doing this manually with an edge finder but it seems a bit hacky. Here is what I'm using which only captures closed loops of simple straight lines. I reuse some graph utilities I already use in my application, happy to share that if it's helpful.
const convertEntities = (model: AnyShape, plane: Plane) => {
const edgeFinder = new EdgeFinder()
edgeFinder.inPlane(plane)
const edges = edgeFinder.find(model)
const graph: Graph<{ point: Point }> = {}
edges.forEach((edge) => {
const id0 = edge.startPoint.repr
const id1 = edge.endPoint.repr
graph[id0] ??= {
id: id0,
point: edge.startPoint,
adjacencies: [],
}
graph[id0]?.adjacencies.push({ id: id1 })
graph[id1] ??= {
id: id1,
point: edge.endPoint,
adjacencies: [],
}
graph[id1]?.adjacencies.push({ id: id0 })
})
const graphClusters = getGraphClusters(graph)
const drawings = graphClusters.map((graphCluster) => {
const startNodeId = Object.values(graphCluster)[0]?.id
if (!startNodeId) return undefined
let openLoop = false
let lastNodeId: string
const loop: Point[] = []
const recurse = (nodeId: string) => {
const node = graphCluster[nodeId]!
if (node.adjacencies.length !== 2) {
openLoop = true
return
}
loop.push(node.point)
const nextNodeId = node.adjacencies.find(
(adj) => adj.id !== lastNodeId,
)?.id
if (!nextNodeId) {
openLoop = true
return
}
if (nextNodeId === startNodeId && loop.length > 2) {
return
} else {
lastNodeId = nodeId
recurse(nextNodeId)
}
}
recurse(startNodeId)
if (openLoop) return undefined
const drawing = loop
.reduce((drawingPen, point, i) => {
if (i === 0) {
return drawingPen.movePointerTo([point.x, point.y])
} else {
return drawingPen.lineTo([point.x, point.y])
}
}, draw())
.close()
return drawing
})
return drawings.filter((drawing): drawing is Drawing => !!drawing)
}
I would like to incorporate something in that spirit with pantograph (my attempt at doing the 2d kernel myself). And I definitely see the point in it (I would call it something like drawEdges
)!
In addition to working only with straight lines your implementation does not handle self intersecting loops - and working with organising the loops to have insides and outsides.
That said I would be curious of what you do with the "sketched" entities? It might be possible to achive what you are trying to do without actually drawing again the edges.
Thanks for bringing pantograph to my attention, it looks great. I have used makerjs before for a 2d DXF export application but it didn't work well for my needs (commonly created odd wavy artifacts in the boolean combine operation).
And yes, my implementation was simply to solve my immediate problem so it's not close to a real solution. I have since figured out how to add circular arcs as well by digging down to the opencascade properties of the curves and backsolving for the arc mid-point.
Can you provide an example of how self-intersecting loops would occur on a face? It seemed impossible to occur to me but I could easily be overlooking something.
As far as application, I am using it to capture the edges on this top face formed by a number of sweeps and other operations. The perimeter would be otherwise difficult to do unless I did the 2d boolean operations separately (pantograph?)
After I grab the perimeters, I offset the outside loops inwards and the inside loops outwards to create this relief feature.
I would like to incorporate something in that spirit with pantograph (my attempt at doing the 2d kernel myself). And I definitely see the point in it (I would call it something like
drawEdges
)!In addition to working only with straight lines your implementation does not handle self intersecting loops - and working with organising the loops to have insides and outsides.
That said I would be curious of what you do with the "sketched" entities? It might be possible to achive what you are trying to do without actually drawing again the edges.
Also, can pantograph drawings be used in replicad?
Thanks for the summary! I was thinking of potentially just creating a sketch from the wires in the face - but it would not work (as I think you cannot do the offsets the way you wanted.
You could also draw the shape within the face in 2d with a simple draw
operation, but you would need to either do the math to have thickness (but prone to errors and boring to you yourself when a machine could do) or build it with different offsets (but if memory serves I have only implemented it correctly for loops). So, for now, this is probably the best implementation.
Also, can pantograph drawings be used in replicad?
Not yet. This is my aim - but there are some things that do not work well enough yet to be ready to be publicized outside of issues in the repo 😉 . I have to implement a better way to handle tolerances with geometries first (and potentially also good offsets for some shapes).