Contour a hatch
Moderator: andrew
Forum rules
Always indicate your operating system and QCAD version.
Attach drawing files, scripts and screenshots.
Post one question per topic.
Always indicate your operating system and QCAD version.
Attach drawing files, scripts and screenshots.
Post one question per topic.
Contour a hatch
Hi,
Is there a way to generate contours (boundary lines) around solid hatches?
I have a dwg file of solid hatches with no boundaries and I need to put a different colored boundary line with some thickness around each hatch. Autocad has a "generate boundary" function for this, and I'm looking for something similar. The boundary is just for "looks" from the output of dwg2bmp later - I don't care what type of boundary object it is, as long as it hugs the hatch closely.
I've tried using different hatch Lineweight and Linetype combinations in Qcad, but I haven't found a combination that displays a hatch boundary with nonzero thickness (if it's even there).
Thanks for any help!
Is there a way to generate contours (boundary lines) around solid hatches?
I have a dwg file of solid hatches with no boundaries and I need to put a different colored boundary line with some thickness around each hatch. Autocad has a "generate boundary" function for this, and I'm looking for something similar. The boundary is just for "looks" from the output of dwg2bmp later - I don't care what type of boundary object it is, as long as it hugs the hatch closely.
I've tried using different hatch Lineweight and Linetype combinations in Qcad, but I haven't found a combination that displays a hatch boundary with nonzero thickness (if it's even there).
Thanks for any help!
Re: Contour a hatch
Create a duplicate, set solid filled, Explode.
That would give you only the boundary of a hatch.
Regards,
CVH
That would give you only the boundary of a hatch.
Regards,
CVH
Re: Contour a hatch
Perfect, thank you CVH!
Re: Contour a hatch
To do that GUI procedure without GUI interaction, I'm trying the following (to make a polyline boundary of a hatch entity):Create a duplicate, set solid filled, Explode.
Code: Select all
var addOp = new RAddObjectOperation();
addOp.addObject(pointerToHatchEntity, true, true);
addOp.apply(document);
pointerToHatchEntity.setSolid(true);
var qSharedPointerToHatchBoundary = pointerToHatchEntity.getExploded();
// my issue is on the next three lines
var hatch = new RExplodable();
hatch.castToExplodable(qSharedPointerToHatchBoundary);
pointerToPolylineHatchBoundary = ?
pointerToPolylineHatchBoundary.setGlobalWidth(0.1);
Many thanks for your help!
Re: Contour a hatch
Remark that a boundary is not always one single thing.
The boundary of a Hatch can have more than one boundary loop.
I read in https://www.qcad.org/doc/qcad/latest/de ... dable.html
Implemented in RPolylineData, RPolyline, RSpline, RLeaderData, and RTriangle.
Not for hatches I think.
However there is RHatchEntity.getBoundaryAsPolylines() what returns a list of RPolyline.
And has Shared Pointer support.
I am not fond with the segmentLength as parameter ...
This will rely on explosions of some shapes and that is governed by App.Preferences settings.
Or worse: hardcoded preferences.
Then there is RHatchEntity.getShapes() what is more vage.
The hard way ... With full control of what is going on.
Tile2Hatch (in the pipeline) already uses this ... based on explode.js
Lets have a peek ...
So:
Every boundary loop is stored under the hatch entity
How many loops: entity.getLoopCount()
To get a loop: news = entity.getLoopBoundary(m) (m is the loop number)
How many entities in a loop: news.length
To get the entities: loopShape = news[n].data() (n is the shape number)
Can be : Line, Arc, full Arc, Spline, Ellipse
BTW: Tile2Hatch send these to itself to further aproximate them with line pieces to reuse as a hatch.
shapes = Tile2Hatch.linApproxEntity(shapeToEntity(doc, news[n].data()), options);
But that you don't need.
The point is now to reconstruct a poly from the resulting loopShapes.
(not 'shape' nor 'shapes' in the code above)
Line & Arc are simple, add poly nodes & adapt for bulging. (There are resources for that)
A circle or a full Arc is a shape that is a loop on its own. (Closed splines and full ellipses too)
A full arc isn't possible in a poly, a math thing.
So you have to splice that up in two semi circle arcs before creating a stand-alone poly.
Splines and ellipse are to be converted/exploded to polylines.
Several options present. see RSplineEntity and REllipseEntity or the data variant.
Regards,
CVH
The boundary of a Hatch can have more than one boundary loop.
I read in https://www.qcad.org/doc/qcad/latest/de ... dable.html
Implemented in RPolylineData, RPolyline, RSpline, RLeaderData, and RTriangle.
Not for hatches I think.
However there is RHatchEntity.getBoundaryAsPolylines() what returns a list of RPolyline.
And has Shared Pointer support.
I am not fond with the segmentLength as parameter ...
This will rely on explosions of some shapes and that is governed by App.Preferences settings.
Or worse: hardcoded preferences.
Then there is RHatchEntity.getShapes() what is more vage.
The hard way ... With full control of what is going on.
Tile2Hatch (in the pipeline) already uses this ... based on explode.js
Lets have a peek ...
Code: Select all
else if (isHatchEntity(entity)) { // Functional SPLINES in painterPaths???
//debugger;
// Check IsNOT Solid: Process painterPaths
if (!entity.isSolid()) { // When patterned
.
..
...
Code to approximate the pattern of a hatch with lines and dots
For the moment this will swap to debug on catching splines in painterpaths
Don't worry, this is the patterned section
...
..
.
}
// Check if is Solid or if asked to export the boundary: Process boundary
if (entity.isSolid() || options.includeBoundary) {
for (m=0; m<entity.getLoopCount(); m++) { // Cycle loops
news = entity.getLoopBoundary(m);
// Can be : Line, Arc, full Arc, Spline, Ellipse
// # Weak # No test for news.length > 0
for (n=0; n<news.length; n++) { // Cycle new-ones
// Recursively handle boundary loop entities:
shapes = Tile2Hatch.linApproxEntity(shapeToEntity(doc, news[n].data()), options);
// # Weak # No test for shapes.length > 0
for (k=0; k<shapes.length; k++) { // Cycle shapes
shape = shapes[k];
ret.push(shape.clone());
} // Loop shapes
} // Loop new-ones
} // Loop boundary loops
} // End boundary
} // End isHatchEntity
Every boundary loop is stored under the hatch entity
How many loops: entity.getLoopCount()
To get a loop: news = entity.getLoopBoundary(m) (m is the loop number)
How many entities in a loop: news.length
To get the entities: loopShape = news[n].data() (n is the shape number)
Can be : Line, Arc, full Arc, Spline, Ellipse
BTW: Tile2Hatch send these to itself to further aproximate them with line pieces to reuse as a hatch.
shapes = Tile2Hatch.linApproxEntity(shapeToEntity(doc, news[n].data()), options);
But that you don't need.
The point is now to reconstruct a poly from the resulting loopShapes.
(not 'shape' nor 'shapes' in the code above)
Line & Arc are simple, add poly nodes & adapt for bulging. (There are resources for that)
A circle or a full Arc is a shape that is a loop on its own. (Closed splines and full ellipses too)
A full arc isn't possible in a poly, a math thing.
So you have to splice that up in two semi circle arcs before creating a stand-alone poly.
Splines and ellipse are to be converted/exploded to polylines.
Several options present. see RSplineEntity and REllipseEntity or the data variant.
Regards,
CVH
Re: Contour a hatch
Thanks for your suggestions, CVH.
I'm attempting your 'easy way', as. My hatch boundary doesn't have to exactly hug the boundary, so some minimum segmentLength of the returned polyline doesn't bother me (if that's what segmentLength means).
In one instance of the easy way, hatchPolylines gets a single RPolyline entity. I know this because the debugger shows that hatchPolylines has taken the value "RPolyline(RShape(address: "0xfffffffff4ac5340"), vertices: ("RVector(-0.001595, 25.171929, 0.000000, 1)", "RVector(-0.001595, 0.117009, 0.000000, 1)...bulges: (0, 0, 0, ..., start widths: (0, 0, 0,... end widths: (0, 0, 0, ...)".
I can do hatchPolylines[0].setGlobalWidth(0.02); without error, since the debugger shows that 'start widths' and 'end widths' have all been changed to 0.02.
Now I need to add the hatchPolylines[0] RPolyine entity onto the the document. I've attempted three methods...
(1)
var expAddOp = new RAddObjectOperation();
expAddOp.addObject(hatchPolylines[0], true, true);
I get the error "RAddObjectsOperation: Argument 0 is not of type RObject".
(2)
var clip = new RClipboardOperation();
clip.copyEntityLinetype(hatchPolylines[0], document, document, true, new RTransaction(storage));
clip.apply(document);
I get the error "RClipboardOperation: Argument 0 is not of type REntity*".
(3)
var ret = [];
ret.push(hatchPolylines[0].clone());
Gives no error, but dosn't seem to do anything.
... RPolyline is a subclass of RObject and REntity, so I don't know why method (1) and (2) can't add the polyline from getBoundaryAsPolyLines() to the document. Is there some casting that I need to do?
I've started looking at your 'hard way' in the meantime.
I'm attempting your 'easy way', as
Code: Select all
hatchPolylines = myHatchEntity.getBoundaryAsPolyLines(double segmentLength)
In one instance of the easy way, hatchPolylines gets a single RPolyline entity. I know this because the debugger shows that hatchPolylines has taken the value "RPolyline(RShape(address: "0xfffffffff4ac5340"), vertices: ("RVector(-0.001595, 25.171929, 0.000000, 1)", "RVector(-0.001595, 0.117009, 0.000000, 1)...bulges: (0, 0, 0, ..., start widths: (0, 0, 0,... end widths: (0, 0, 0, ...)".
I can do hatchPolylines[0].setGlobalWidth(0.02); without error, since the debugger shows that 'start widths' and 'end widths' have all been changed to 0.02.
Now I need to add the hatchPolylines[0] RPolyine entity onto the the document. I've attempted three methods...
(1)
var expAddOp = new RAddObjectOperation();
expAddOp.addObject(hatchPolylines[0], true, true);
I get the error "RAddObjectsOperation: Argument 0 is not of type RObject".
(2)
var clip = new RClipboardOperation();
clip.copyEntityLinetype(hatchPolylines[0], document, document, true, new RTransaction(storage));
clip.apply(document);
I get the error "RClipboardOperation: Argument 0 is not of type REntity*".
(3)
var ret = [];
ret.push(hatchPolylines[0].clone());
Gives no error, but dosn't seem to do anything.
... RPolyline is a subclass of RObject and REntity, so I don't know why method (1) and (2) can't add the polyline from getBoundaryAsPolyLines() to the document. Is there some casting that I need to do?
I've started looking at your 'hard way' in the meantime.
Re: Contour a hatch
Ok, got some success by starting with your "hard way". In the code below, I first get each loopShape as an entity with shapeToEntity() and then set its PropertyLineweight, which is common to all Line, Arc, Spline, Ellipse, and Circle entities. This way I don't have to form a polyline from all of the loopShapes (and also avoid splitting up a circle or full arc as you mentioned). So I'm not longer setting the hatch boundary thickness by polylineEntity.setGlobalWidth(0.02)) but rather by loopEntity.setLineWeight(RLineweight.Weight070).
The code below successfully puts visible boundary shape entities around each hatch, but their thickness is "Bylayer" instead of the specified 'Weight070'. There is a similar problem with the code below not putting loopEntity on the right layer (every loopEntity is on layer 0 instead of layer ID = oLayerIds). Any idea why the thicknesses and layers aren't set correctly?
The code below successfully puts visible boundary shape entities around each hatch, but their thickness is "Bylayer" instead of the specified 'Weight070'. There is a similar problem with the code below not putting loopEntity on the right layer (every loopEntity is on layer 0 instead of layer ID = oLayerIds). Any idea why the thicknesses and layers aren't set correctly?
Code: Select all
var op = new RAddObjectOperation();
for (var m=0; m<hatchEntity.getLoopCount(); m++) { // Cycle loops
news = hatchEntity.getLoopBoundary(m);
// Can be : Line, Arc, full Arc, Spline, Ellipse
// # Weak # No test for news.length > 0
for (var n=0; n<news.length; n++) { // Cycle new-ones
// Recursively handle boundary loop entities:
loopShape = news[n].data();
var loopEntity = shapeToEntity(document,loopShape);
loopEntity.setLineweight(RLineweight.Weight070);
loopEntity.setLayerId(oLayerIds[i]);
op.addObject(loopEntity);
} // Loop new-ones
} // Loop boundary loops
di.applyOperation(op);
Re: Contour a hatch
So you dropped poly as boundary route.
I would wipe the line: '// Recursively handle boundary loop entities:' because your code isn't recursive.
Your first trials are missing shapeToEntity() I think.
What you are doing is fairly the same as addshape from simple_create.js
You could use addshape directly, or addshapes ... remember to include simple.js
Odd why it doesn't work out.
Lets have a look at explode.js about line 295.
The shape is derived from shapes(n) not shapes(n).data (recursive I needed that)
The shape is cloned and collected (you have to work on a copy)
The collection is casted in line 119 and on
Maybe that helps.
The layer thing I solve with setting the current layer.
Something with the layer of an entity in a drawing vs an entity from a shape to put in a drawing.
Fuzzy I know. I useally solve this with trials and error.
Regards,
CVH
I would wipe the line: '// Recursively handle boundary loop entities:' because your code isn't recursive.
Your first trials are missing shapeToEntity() I think.
What you are doing is fairly the same as addshape from simple_create.js
You could use addshape directly, or addshapes ... remember to include simple.js
Odd why it doesn't work out.
Lets have a look at explode.js about line 295.
The shape is derived from shapes(n) not shapes(n).data (recursive I needed that)
The shape is cloned and collected (you have to work on a copy)
The collection is casted in line 119 and on
Maybe that helps.
The layer thing I solve with setting the current layer.
Something with the layer of an entity in a drawing vs an entity from a shape to put in a drawing.
Fuzzy I know. I useally solve this with trials and error.
Regards,
CVH
Re: Contour a hatch
CVH, you're correct: if I use addShape() from simple_create.js it should let me control boundary entity linewidths as an argument of any value, e.g. addShape(shape, args, 0.07). This is a better alternative to what I have working now, which is to get loop boundary shapes as entities and then set their line weights by only the discrete options in RLineweight, e.g. loopEntity.setLineweight(RLineweight.Weight070).
So I tried using addShape() in a few different ways (with library.js, simple.js, simple_create.js and simple_modify.js all included), and the script runs without error but unfortunately addShape() didn't add any entity onto the document. I have two questions to troubleshoot this:
1. Onto which document are the addShape() entities being added? From the API, addShape() puts the entity on "the document", but I have two documents always open in my script: originalDocument, and document, which is a copy of originalDocument. originalDocument is not used in any of the code posted here but it stays loaded while the script runs and is used later. I didn't find an explicit way to control which document addShape() operates on. In the code below, is an entity already on document, so does that mean that addShape() entities are placed by default on document and not on originalDocument?
2. Is a transaction event required to add the addshape() entities to the document? From the API, addShape() looks like it returns void but the description states that it returns "the added entity. The entity does not yet have a valid ID if it was added within a transaction." If an RAddObjectsOperation transaction is required to add the addShape() entities to the document, then how would I even access those entities given that results in addedEntities being undefined? So I don't know how to access the entities to even add them to a transaction.
What I have:
Here I tried using addShape() without a transaction. This code results in no error and no addShape() entities added to document.
Here I tried using addShape() without transaction just as a workaround to setting RLineweight.Weight070. Below is the pseudocode first, then actual code further down:
loopShape = solidHatchEntity.loopBoundary()
loopEntity = loopShape.shapeToEntity() //shape to entity
<set some non-lineweight loopEntity properties>
shape = loopEntity.castToShape() //now go back to shape to set any lineweight
addShape(shape, args, 0.07) //adds shape as entity to "the document"
This code results in no error and no addShape() entities added to document.
So I tried using addShape() in a few different ways (with library.js, simple.js, simple_create.js and simple_modify.js all included), and the script runs without error but unfortunately addShape() didn't add any entity onto the document. I have two questions to troubleshoot this:
1. Onto which document are the addShape() entities being added? From the API, addShape() puts the entity on "the document", but I have two documents always open in my script: originalDocument, and document, which is a copy of originalDocument. originalDocument is not used in any of the code posted here but it stays loaded while the script runs and is used later. I didn't find an explicit way to control which document addShape() operates on. In the code below,
Code: Select all
solidHatchEntity
2. Is a transaction event required to add the addshape() entities to the document? From the API, addShape() looks like it returns void but the description states that it returns "the added entity. The entity does not yet have a valid ID if it was added within a transaction." If an RAddObjectsOperation transaction is required to add the addShape() entities to the document, then how would I even access those entities given that
Code: Select all
var addedEntities = addshape(shape, args)
What I have:
Here I tried using addShape() without a transaction. This code results in no error and no addShape() entities added to document.
Code: Select all
// >>
for (var m=0; m<solidHatchEntity.getLoopCount(); m++) { // Cycle loops
shapes = solidHatchEntity.getLoopBoundary(m);
// Can be : Line, Arc, full Arc, Spline, Ellipse
for (var n=0; n<shapes.length; n++) { // Cycle shapes
// add RShape to the drawing as a new entity with current layer and attributes. The entity does not yet have a valid ID if it was added within a transaction.
addShape(shapes[n],new RColor (50,50,50),"CONTINUOUS", 0.07);
}
}
Here I tried using addShape() without transaction just as a workaround to setting RLineweight.Weight070. Below is the pseudocode first, then actual code further down:
loopShape = solidHatchEntity.loopBoundary()
loopEntity = loopShape.shapeToEntity() //shape to entity
<set some non-lineweight loopEntity properties>
shape = loopEntity.castToShape() //now go back to shape to set any lineweight
addShape(shape, args, 0.07) //adds shape as entity to "the document"
This code results in no error and no addShape() entities added to document.
Code: Select all
for (var m=0; m<solidHatchEntity.getLoopCount(); m++) { // Cycle loops
loopShapes = solidHatchEntity.getLoopBoundary(m);
// Can be : Line, Arc, full Arc, Spline, Ellipse
for (var n=0; n<loopShapes.length; n++) { // Cycle new-ones
var loopEntity = shapeToEntity(document,loopShape[m]);
loopEntity.setColor(new RColor(50,50,50));
//loopEntity.setLineweight(RLineweight.Weight070);
var shape = loopEntity.castToShape();
addShape(shape,new RColor (50,50,50),"CONTINUOUS", 0.07);
}
}
Re: Contour a hatch
addShape runs within a transaction.
Best example I could find regarding your usage is:
...qcad-master 3.24\qcad-master\scripts\Misc\Examples\MathExamples\ExMandelbrot\ExMandelbrot.js
startTransaction needs a DocumentInterface so I presume the document thing is covered.
Regards,
CVH
Best example I could find regarding your usage is:
...qcad-master 3.24\qcad-master\scripts\Misc\Examples\MathExamples\ExMandelbrot\ExMandelbrot.js
startTransaction needs a DocumentInterface so I presume the document thing is covered.
Regards,
CVH
Re: Contour a hatch
Ah, that's a much a simpler solution than I was trying
startTransaction(documentInterface);
addShape(shape, new RColor(r,g,b), "CONTINUOUS", 0.07);
endTransaction();
works!
Thanks so much for the help!
startTransaction(documentInterface);
addShape(shape, new RColor(r,g,b), "CONTINUOUS", 0.07);
endTransaction();
works!
Thanks so much for the help!