win10 QCAD3.28.2 PRO
Hello everyone, the attachment is a DXF test file I designed, which contains a hatch area. I am now using the winform netdxf library to parse this DXF file. The obtained hatch entity contains four netDxf.Entities.HatchBoundaryPath objects, but I don’t know this. Which two of the four objects need to be filled and which two do not need to be filled? Is there any flag or method to distinguish them? I need to display the filled area in winform program
hatch problem
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.
-
- Full Member
- Posts: 84
- Joined: Fri Oct 20, 2023 7:21 am
hatch problem
- Attachments
-
- 填充-多图.dxf
- (97.57 KiB) Downloaded 159 times
-
- VeryCapture_20231124100314.jpg (249.89 KiB) Viewed 5608 times
Re: hatch problem
Hi,
This is an island in an island in an ... problem.
You have to determine what HatchBoundaryPath is (fully) inside the other.
Easy for humans to do that: [0] is inside [2], [2] is inside [1] and all that is inside [3].
The QCAD hatch engine does this automatically given some rules of engagement to render a hatch.
It gets tricky when loops are self-intersecting or intersecting with other loops.
Not all applications will render these special cases the same way.
Here you may find an image of a very odd hatch with one single boundary loop:
https://www.qcad.org/rsforum/viewtopic. ... 052#p39052
Some applications may render this as completely filled.
And for example TTF fonts are outlines rendered filled disregarding open islands.
Detecting which loop is inside the other is not straightforward.
It is a process of detection and elimination based on all shapes from all boundary paths.
Verifying isLeft or isRight regarding the shapes of the other loop(s).
With an ellipse or an ellipse arc that is mathematically fairly impossible, usually those are approximated with arc-segments.
And somewhat similar for edges that are splines or spline segments.
Arcs may impose other problems as they don't have a start or endpoint, they have start and end angles.
Comparing things requires some degree of tolerance (usually absolute) to account for Floating Point (relative) uncertainty.
Regards,
CVH
This is an island in an island in an ... problem.
You have to determine what HatchBoundaryPath is (fully) inside the other.
Easy for humans to do that: [0] is inside [2], [2] is inside [1] and all that is inside [3].
The QCAD hatch engine does this automatically given some rules of engagement to render a hatch.
It gets tricky when loops are self-intersecting or intersecting with other loops.
Not all applications will render these special cases the same way.
Here you may find an image of a very odd hatch with one single boundary loop:
https://www.qcad.org/rsforum/viewtopic. ... 052#p39052
Some applications may render this as completely filled.
And for example TTF fonts are outlines rendered filled disregarding open islands.
Detecting which loop is inside the other is not straightforward.
It is a process of detection and elimination based on all shapes from all boundary paths.
Verifying isLeft or isRight regarding the shapes of the other loop(s).
With an ellipse or an ellipse arc that is mathematically fairly impossible, usually those are approximated with arc-segments.
And somewhat similar for edges that are splines or spline segments.
Arcs may impose other problems as they don't have a start or endpoint, they have start and end angles.
Comparing things requires some degree of tolerance (usually absolute) to account for Floating Point (relative) uncertainty.
Regards,
CVH
-
- Full Member
- Posts: 84
- Joined: Fri Oct 20, 2023 7:21 am
Re: hatch problem
HI CVH
For hatches, I don’t need to consider too complicated scenarios. There are two areas that need to be filled in the attachment. Each filled area is determined by two HatchBoundaryPaths. My problem is that I cannot determine the HatchBoundaryPath pair corresponding to each hatch. I searched I've searched a lot of information but can't find the corresponding relationship. Can you give me some guidance?
For hatches, I don’t need to consider too complicated scenarios. There are two areas that need to be filled in the attachment. Each filled area is determined by two HatchBoundaryPaths. My problem is that I cannot determine the HatchBoundaryPath pair corresponding to each hatch. I searched I've searched a lot of information but can't find the corresponding relationship. Can you give me some guidance?
Re: hatch problem
The most minimalistic approach would be to take a point on each BoundaryPath and verify if that is inside the other BoundaryPath's.
This method makes several assumptions:
- Any random point on a BoundaryPath will do
- Locally a number of boundary loops except one are inside other loops
- Boundary loops do not touch others
- Boundary loops do not intersect with others
- Boundary loops do not self-intersect
- ...
And in a way you need to verify all these conditions.
The QCAD resources have some methods to accomplish the minimalistic approach.
The second part of the code below is typically implemented as a function to determine the order of the BoundaryPath's nested nature.
You are not out the woods yet.
Let's assume this returns [0, 2, 1].
An even count is filled, an uneven not, loop 2 is inside loop 3 and all that is inside loop 1.
So far so good. Note that I index loops starting with 1, an array index is zero based.
With 4 loops this may return [0, 2, 0, 1].
Loops 1 and 3 are not inside another loop, loop 2 is most likely inside 4 but it doesn't tell you if loop 4 is inside 1 or inside 3.
And even harder with this 5 loops example [0, 2, 0, 1, 1] ... 4 and 5 may be both or not inside 1 or 3, 2 is inside 4 or 5.
Per definition it is thus not strictly pairwise as you described it.
Having the nesting order it is a question of further determination of what is inside what starting with the highest order(s).
I don't think this can be coded along with the code of the above routine there you can not predict the outcome of a yet untested nesting order.
Note that curved boundary shapes are approximated by short line segments, which simplifies the internal math.
This may be sufficient for most purposes ...
Too coarse it may return rubbish, way too fine the contain algorithm may take forever.
Another method may rely on a point inside a certain area to fill or not.
Counting the times that a ray starting in this point intersects with the boundary loops.
Even or uneven intersections is then again related to hatched or not, intersecting or self-intersecting loops are accounted for.
The trouble here is that the number of intersections may vary according the tested orientation.
With even and uneven counts it is not uniquely defined if an enclosed area should be filled or not.
In these complex situations other rules need to be implemented.
Regards,
CVH
This method makes several assumptions:
- Any random point on a BoundaryPath will do
- Locally a number of boundary loops except one are inside other loops
- Boundary loops do not touch others
- Boundary loops do not intersect with others
- Boundary loops do not self-intersect
- ...
And in a way you need to verify all these conditions.
The QCAD resources have some methods to accomplish the minimalistic approach.
The second part of the code below is typically implemented as a function to determine the order of the BoundaryPath's nested nature.
Code: Select all
var hatchEntity; // A hatch entity queried from the document
var segmentLength; // Segment length to approximate curved line-art
// = = = = = = = = =
var loops = hatchEntity.getBoundaryAsPolylines(segmentLength);
var nestOrders = []
var iMax = loops.length;
if (iMax < 1) return undefined; // Failed, no boundary loops
if (iMax < 2) return [0]; // Single boundary loop
// Process all hatch boundary loops for their nested nature:
for (var i=0; i<iMax; i++) {
var loop = loops[i];
// Verify with other boundary loops:
var nested = 0;
var point = loop.getStartPoint();
for (var j=0; j<iMax; j++) {
if (i === j) continue; // Skip itself
var trial = loops[j];
// Verify if the boundary is nested inside the one on trial:
// A) Exclude boundaries that are not even close box based:
if (!trial.getBoundingBox().contains(loop.getBoundingBox())) {
continue; // Is not nested
}
// B) Verify if a random vertex is inside the trial boundary.
if (trial.contains(point, false, RS.PointTolerance)) { // NotOn poly with tolerance = 1e-9
nested++; // Is nested in loop
}
}
// Collect the order of the nested nature:
nestOrders.push(nested);
}
return nestOrders;
Let's assume this returns [0, 2, 1].
An even count is filled, an uneven not, loop 2 is inside loop 3 and all that is inside loop 1.
So far so good. Note that I index loops starting with 1, an array index is zero based.
With 4 loops this may return [0, 2, 0, 1].
Loops 1 and 3 are not inside another loop, loop 2 is most likely inside 4 but it doesn't tell you if loop 4 is inside 1 or inside 3.
And even harder with this 5 loops example [0, 2, 0, 1, 1] ... 4 and 5 may be both or not inside 1 or 3, 2 is inside 4 or 5.
Per definition it is thus not strictly pairwise as you described it.
Having the nesting order it is a question of further determination of what is inside what starting with the highest order(s).
I don't think this can be coded along with the code of the above routine there you can not predict the outcome of a yet untested nesting order.
Note that curved boundary shapes are approximated by short line segments, which simplifies the internal math.
This may be sufficient for most purposes ...
Too coarse it may return rubbish, way too fine the contain algorithm may take forever.
Another method may rely on a point inside a certain area to fill or not.
Counting the times that a ray starting in this point intersects with the boundary loops.
Even or uneven intersections is then again related to hatched or not, intersecting or self-intersecting loops are accounted for.
The trouble here is that the number of intersections may vary according the tested orientation.
With even and uneven counts it is not uniquely defined if an enclosed area should be filled or not.
In these complex situations other rules need to be implemented.
Regards,
CVH
Last edited by CVH on Tue Nov 28, 2023 3:13 pm, edited 1 time in total.
Re: hatch problem
The 2-3 Loops below are not complicated, each one is a simple convex polygon.WildWolfCJ wrote: ↑Tue Nov 28, 2023 3:05 amFor hatches, I don’t need to consider too complicated scenarios
Not when the loops are intersecting. Then the enclosed area of a single loop may be filled but also not filled.WildWolfCJ wrote: ↑Tue Nov 28, 2023 3:05 amEach filled area is determined by two HatchBoundaryPaths.
The minimalistic approach will not work there both startpoints of the yellow and orange loop are not inside the other.
On the bottom row the yellow and orange loop are both 1 level inside the white loop.
Because you make the assumption that it is a simple pairwise relationship what is only the case for trivial layouts.WildWolfCJ wrote: ↑Tue Nov 28, 2023 3:05 amMy problem is that I cannot determine the HatchBoundaryPath pair corresponding to each hatch.
You first need to establish that it is indeed a trivial case.
Some examples:
With a simple flag (Not supported by QCAD) the resulting hatched areas may look like the examples below.
Bottom line, DXF only stores the geometry of the loops, what can be in any order.
It is up to the application to render the hatched area as required.
Regards,
CVH
-
- Full Member
- Posts: 84
- Joined: Fri Oct 20, 2023 7:21 am
Re: hatch problem
HI CVH
I now use a very simple way to deal with this problem. Of course, my method is very imperfect. I calculate the area of each graphic based on HatchBoundaryPath, and then fill it in pairs according to the area size. Your method is so complicated that it is difficult for me to implement it.
I now use a very simple way to deal with this problem. Of course, my method is very imperfect. I calculate the area of each graphic based on HatchBoundaryPath, and then fill it in pairs according to the area size. Your method is so complicated that it is difficult for me to implement it.
Re: hatch problem
It is not my method but a method for trivial cases.WildWolfCJ wrote: ↑Wed Nov 29, 2023 7:50 amYour method is so complicated that it is difficult for me to implement it.
Disregarding that loops can self-intersect and then the area calculation may be incorrect or complete rubbish depending the algorithm.WildWolfCJ wrote: ↑Wed Nov 29, 2023 7:50 amI calculate the area of each graphic based on HatchBoundaryPath, and then fill it in pairs according to the area size.
Disregarding that loops may intersect each other and then the area value isn't a correct indication factor.
How correct/robust are your resources for the elliptic arc area, spline area, polylines with arcs or chain of arcs area?
Most likely only fit for clean 1 IN 1 relations.
What if there are two islands side by side?
Regards,
CVH