Skip to content

Commit 6f2fb7e

Browse files
authored
new utility to create scan paths (#42)
* new utility to create scan paths * clean-up: removed nfs file clean
1 parent b0fa890 commit 6f2fb7e

File tree

6 files changed

+538
-33
lines changed

6 files changed

+538
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
createScanPath.C
2+
3+
EXE = $(FOAM_USER_APPBIN)/createScanPath
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
EXE_INC = \
2+
-I$(LIB_SRC)/finiteVolume/lnInclude \
3+
-I$(LIB_SRC)/meshTools/lnInclude
4+
5+
EXE_LIBS = \
6+
-lfiniteVolume \
7+
-lmeshTools
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
/*---------------------------------------------------------------------------*\
2+
========= |
3+
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4+
\\ / O peration | Website: https://openfoam.org
5+
\\ / A nd | Copyright (C) 2024 OpenFOAM Foundation
6+
\\/ M anipulation |
7+
-------------------------------------------------------------------------------
8+
Copyright (C) 2023 Oak Ridge National Laboratory
9+
-------------------------------------------------------------------------------
10+
License
11+
This file is part of OpenFOAM.
12+
13+
OpenFOAM is free software: you can redistribute it and/or modify it
14+
under the terms of the GNU General Public License as published by
15+
the Free Software Foundation, either version 3 of the License, or
16+
(at your option) any later version.
17+
18+
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21+
for more details.
22+
23+
You should have received a copy of the GNU General Public License
24+
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25+
26+
SourceFiles
27+
createScanPath.C
28+
29+
\*---------------------------------------------------------------------------*/
30+
31+
#include "fvCFD.H"
32+
#include "OFstream.H"
33+
#include <algorithm>
34+
#include <fstream>
35+
#include <iomanip>
36+
#include <sstream>
37+
#include <vector>
38+
39+
namespace Foam
40+
{
41+
42+
/*---------------------------------------------------------------------------*\
43+
Struct Point Definition
44+
\*---------------------------------------------------------------------------*/
45+
46+
struct Point
47+
{
48+
scalar x;
49+
scalar y;
50+
51+
// Default constructor
52+
Point()
53+
: x( 0.0 )
54+
, y( 0.0 )
55+
{
56+
}
57+
58+
// Construct from x and y
59+
Point( scalar xCoord, scalar yCoord )
60+
: x( xCoord )
61+
, y( yCoord )
62+
{
63+
}
64+
65+
// Function to rotate a point around a specified origin by a given angle
66+
Point rotate( const Point& origin, scalar degrees ) const
67+
{
68+
scalar angle = degrees * ( M_PI / 180.0 );
69+
70+
scalar s = sin( angle );
71+
scalar c = cos( angle );
72+
scalar translatedX = x - origin.x;
73+
scalar translatedY = y - origin.y;
74+
scalar newX = translatedX * c - translatedY * s + origin.x;
75+
scalar newY = translatedX * s + translatedY * c + origin.y;
76+
return Point( newX, newY );
77+
}
78+
79+
// Define a custom operator<< to print a Point
80+
friend std::ostream& operator<<( std::ostream& os, const Point& point )
81+
{
82+
os << "(" << point.x << ", " << point.y << ")";
83+
return os;
84+
}
85+
};
86+
87+
// Function to calculate the distance between two points
88+
scalar distance( const Point& p1, const Point& p2 )
89+
{
90+
scalar dx = p1.x - p2.x;
91+
scalar dy = p1.y - p2.y;
92+
return std::sqrt( dx * dx + dy * dy );
93+
}
94+
95+
96+
/*---------------------------------------------------------------------------*\
97+
Struct Line Definition
98+
\*---------------------------------------------------------------------------*/
99+
100+
struct Line
101+
{
102+
Point start;
103+
Point end;
104+
105+
// Default constructor
106+
Line()
107+
: start( Point() )
108+
, end( Point() )
109+
{
110+
}
111+
112+
// Construct from two points
113+
Line( Point startPoint, Point endPoint )
114+
: start( startPoint )
115+
, end( endPoint )
116+
{
117+
}
118+
119+
// Function to rotate the line around a specified origin by a given angle
120+
void rotate( const Point& origin, scalar angle )
121+
{
122+
start = start.rotate( origin, angle );
123+
end = end.rotate( origin, angle );
124+
}
125+
126+
bool isFinite()
127+
{
128+
return ( !std::isnan( start.x ) && !std::isnan( start.y ) &&
129+
!std::isnan( end.x ) && !std::isnan( end.y ) );
130+
}
131+
132+
// Define a custom operator<< to print a Line
133+
friend std::ostream& operator<<( std::ostream& os, const Line& line )
134+
{
135+
os << "(" << line.start.x << ", " << line.start.y << "), "
136+
<< "(" << line.end.x << ", " << line.end.y << ")";
137+
return os;
138+
}
139+
};
140+
141+
142+
/*---------------------------------------------------------------------------*\
143+
Struct BoundBox Definition
144+
\*---------------------------------------------------------------------------*/
145+
146+
struct BoundBox
147+
{
148+
Point minPoint;
149+
Point maxPoint;
150+
Point midPoint;
151+
152+
std::vector<Line> edges;
153+
154+
// Construct from two points
155+
BoundBox( Point minP, Point maxP )
156+
: minPoint( minP )
157+
, maxPoint( maxP )
158+
, midPoint( ( minP.x + maxP.x ) / 2.0, ( minP.y + maxP.y ) / 2.0 )
159+
{
160+
// left, right, top, bottom
161+
edges = { { Point( minPoint.x, minPoint.y ),
162+
Point( minPoint.x, maxPoint.y ) },
163+
{ Point( maxPoint.x, minPoint.y ),
164+
Point( maxPoint.x, maxPoint.y ) },
165+
{ Point( minPoint.x, maxPoint.y ),
166+
Point( maxPoint.x, maxPoint.y ) },
167+
{ Point( minPoint.x, minPoint.y ),
168+
Point( maxPoint.x, minPoint.y ) } };
169+
}
170+
171+
// Function to check if a point is inside the bounding box
172+
bool isInside( Point p )
173+
{
174+
return p.x >= minPoint.x && p.x <= maxPoint.x && p.y >= minPoint.y &&
175+
p.y <= maxPoint.y;
176+
}
177+
178+
Line cropLine( const Line& line )
179+
{
180+
std::vector<Point> intersections;
181+
182+
for ( const Line& edge : edges )
183+
{
184+
Point intersection = intersect( edge, line );
185+
186+
if ( !std::isnan( intersection.x ) &&
187+
!std::isnan( intersection.y ) )
188+
{
189+
intersections.push_back( intersection );
190+
}
191+
}
192+
193+
if ( intersections.size() == 0 )
194+
{
195+
return Line( Point( NAN, NAN ), Point( NAN, NAN ) );
196+
}
197+
198+
// Sort intersection points based on position along the original line
199+
std::sort( intersections.begin(), intersections.end(),
200+
[&line]( const Point& p1, const Point& p2 )
201+
{
202+
scalar d1 = distance( line.start, p1 );
203+
scalar d2 = distance( line.start, p2 );
204+
return d1 < d2;
205+
} );
206+
207+
Line intersectedLine( intersections.front(), intersections.back() );
208+
209+
return intersectedLine;
210+
}
211+
212+
// Function to find the intersection point between two lines
213+
Point intersect( const Line& line1, const Line& line2 )
214+
{
215+
Point intersection( std::numeric_limits<scalar>::quiet_NaN(),
216+
std::numeric_limits<scalar>::quiet_NaN() );
217+
218+
// components of first line
219+
scalar x1 = line1.start.x;
220+
scalar y1 = line1.start.y;
221+
scalar x2 = line1.end.x;
222+
scalar y2 = line1.end.y;
223+
224+
// components of second line
225+
scalar x3 = line2.start.x;
226+
scalar y3 = line2.start.y;
227+
scalar x4 = line2.end.x;
228+
scalar y4 = line2.end.y;
229+
230+
scalar denominator =
231+
( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 );
232+
233+
// Lines are parallel or colinear, no intersection
234+
if ( denominator == 0 )
235+
{
236+
return intersection;
237+
}
238+
239+
scalar t = ( ( x1 - x3 ) * ( y3 - y4 ) - ( y1 - y3 ) * ( x3 - x4 ) ) /
240+
denominator;
241+
242+
scalar u = -( ( x1 - x2 ) * ( y1 - y3 ) - ( y1 - y2 ) * ( x1 - x3 ) ) /
243+
denominator;
244+
245+
if ( t >= 0 && t <= 1 && u >= 0 && u <= 1 )
246+
{
247+
intersection.x = x1 + t * ( x2 - x1 );
248+
intersection.y = y1 + t * ( y2 - y1 );
249+
return intersection;
250+
}
251+
252+
return intersection;
253+
}
254+
};
255+
256+
257+
/*---------------------------------------------------------------------------*\
258+
Struct Path Definition
259+
\*---------------------------------------------------------------------------*/
260+
261+
struct Path
262+
{
263+
std::vector<Line> lines;
264+
scalar power;
265+
scalar speed;
266+
scalar dwellTime;
267+
268+
// Construct the path from a bounding box and hatch spacing
269+
270+
// Default constructor
271+
Path() {}
272+
273+
// Constructor from components
274+
Path(const BoundBox& bbox, const scalar step, const scalar angle)
275+
{
276+
createPath(bbox, step, angle);
277+
}
278+
279+
// Function to create path from components
280+
void createPath(BoundBox bbox, const scalar step, const scalar angle)
281+
{
282+
label n = countLines( bbox, step );
283+
284+
// create a pad of infinitely long, equally parallel lines
285+
std::vector<Line> pathLines;
286+
287+
const scalar great = 1e10;
288+
289+
// Create lines in the negative direction, excluding the midpoint line
290+
for ( label i = n - 1; i > 0; --i )
291+
{
292+
scalar height = bbox.midPoint.y - i * step;
293+
Line currentLine( Point( -great, height ), Point( great, height ) );
294+
pathLines.push_back( currentLine );
295+
}
296+
297+
// Create lines in the positive direction, including the midpoint
298+
for ( label i = 0; i < n; ++i )
299+
{
300+
scalar height = bbox.midPoint.y + i * step;
301+
Line currentLine( Point( -great, height ), Point( great, height ) );
302+
pathLines.push_back( currentLine );
303+
}
304+
305+
// apply rotation and cropping to the initial lines
306+
for ( const Line& pathLine : pathLines )
307+
{
308+
// Rotate the endpoints by the specified angle
309+
Line rotatedLine = pathLine;
310+
rotatedLine.rotate( bbox.midPoint, angle );
311+
312+
Line croppedLine = bbox.cropLine( rotatedLine );
313+
314+
if ( croppedLine.isFinite() )
315+
{
316+
lines.push_back( croppedLine );
317+
}
318+
}
319+
}
320+
321+
// Function to find the number of scan vectors in the bounding box
322+
label countLines( const BoundBox& bbox, scalar step ) const
323+
{
324+
label nX = 0;
325+
label nY = 0;
326+
327+
for ( scalar x = bbox.minPoint.x; x <= bbox.maxPoint.x; x += step )
328+
{
329+
nX++;
330+
}
331+
332+
for ( scalar y = bbox.minPoint.y; y <= bbox.maxPoint.y; y += step )
333+
{
334+
nY++;
335+
}
336+
337+
return ( nX > nY ) ? nX : nY;
338+
}
339+
340+
void write( const std::string& filename,
341+
const bool bi_direction = true ) const
342+
{
343+
std::ofstream file( filename );
344+
345+
file << "Mode\tX(m)\tY(m)\tZ(m)\tPower(W)\ttParam" << std::endl;
346+
347+
for ( size_t i = 0; i < lines.size(); ++i )
348+
{
349+
const Line& line = lines[i];
350+
351+
Point first = line.start;
352+
Point second = line.end;
353+
354+
// reverse the odd lines for bi_directional
355+
if ( bi_direction && i % 2 == 1 )
356+
{
357+
first = line.end;
358+
second = line.start;
359+
}
360+
361+
// hatch (with skywrite)
362+
if ( i == 0 )
363+
{
364+
// no initial dwell
365+
file << "1\t" << first.x << "\t" << first.y << "\t0\t0\t0\n";
366+
}
367+
else
368+
{
369+
file << "1\t" << first.x << "\t" << first.y << "\t0\t" << 0
370+
<< "\t" << dwellTime << "\n";
371+
}
372+
373+
// raster
374+
file << "0\t" << second.x << "\t" << second.y << "\t0\t" << power
375+
<< "\t" << speed << "\n";
376+
}
377+
378+
file.close();
379+
}
380+
};
381+
382+
} // End namespace Foam
383+
384+
// ************************************************************************* //

0 commit comments

Comments
 (0)