# Module to generate input datasets for the tool-path algorithms. # Last edited on 2021-06-04 14:50:12 by jstolfi import input_data_IMP # READING OR CREATING DATASETS # The procedures in this section return complete datasets for # the algorithms, such as {hotpath.best_path}, that compute a # tool-path for a slice. # # The raw dataset consists of (1) A list {OCRS} of closed {Path} objects # corresponding to the contours, (2) a list {OPHS} of filler elements, # (3) a list {CTS} of {Contact} objects between those fillers, and (4) the {Z} # coordinate of the slice. # # The contours will be closed paths consisting of traces with parameters # {mp_cont}. The nesting structure of the contours in {OCRS} can be # obtained through {path.inner_contours} and {path.outer_contours}. # # The elements of {OPHS} are a collection of /rasters/ -- single-trace # paths -- that comprise a solid filling for the interior of the slice. # In the current version, the rasters in {OPHS} will all be horizontal, # but oriented arbitrarily, depending on the sourceof the data. They # will all have the same parameters {mp_fill}, and therefore the same # nominal width {wdf = move_parms.width(mp_fill)}. # # The returned list of contacts {CTS} will have all the contacts beween # filler elements of {OPHS}. The contacts of a filler element {oph} will # be available through {path_hp.get_contacts}. For the time being, the # package does not consider contacts between fillers and contours. # # A /scanline/ is a set of rasters fill elements with nearly the same # {Y}-coordinate. In the current version, the raster fill elements in # {OPHS} will be partitioned into scanlines with regular spacing in the # {Y} direction. More precisely, the scanline with index {isc} has {Y} # coordinate approximately {isc*ystep + yphase}, where {ystep} and # {yphase} are constant parameters for the raster fill set. There may be # small deviations from this formula, due to roundoff erors. # # The filling rasters in {OPHS} will be sorted in /scan-line order/, # namely by increasing scanline {Y} (again, ignoring roundoff errors), # and increasing {X} within each scan-line. # # The procedures that read or create raw datasets will assign each # filler element {oph} in {OPHS} to an initial /group/ that is available # through {path_hp.get_group}. These groups are relevant to the assembly # of the filler elements into blocks. See {create_blocks} below. # # Each procedure in this section also creates a set of /link paths/ that # can be used to connect the filler elements in the chosen tool-path. # Each link is associated to the two filler elements that it connects. # The links that end at that start {pini(oph)} of a filler element {oph} # are available through {path_hp.get_links(oph)}, and those that start # at {pfin(oph)} are available through {path_hp.get_links(rev(oph))}, # but reversed. def read_txt(fname, mp_cont, mp_fill, angle, shift): # Reads a raw input data set from the file named # {fname}. The file must be a ".txt" file as created by # the RP3 planning software (possibly modified by # other programs). See {txt_read.read} for the file format and the # meaning of {angle} and {shift}. # # The file specifies, possibly among other things: # # * A set of closed contour polygons possibly nested to arbitrary levels. # # * A set of filler elements, each a single raster trace. # # * A set of links, each being a path that joins the end of some raster # to the end of an adjacent raster. # # * A set of contacts between the filler elements. # # * The {Z} coordinate or the slice # # The procedure digests that information and returns (1) the list # {OCRS} of contours, (2) the list {OPHS} of raster filling elements, # (3) the list {CTS} of contacts, and (4) the {Z} coordinate of the # slice. # # The contour polygons specified in the file are converted into closed # paths for the list {OCRS}. The traces of the path will have # parameters {mp_cont}. # # The raster traces will have parameters {mp_fill}. Each raster # will be oriented as specified by the {rbit} flag in the file. # The names (that can be accessd through {path.get_name) will be # "P{ife}" where {ife} is the index in the input file. # Note that these indices may not match the indices in {OPHS}. # # Each filler element is assigned to the group defined by the {group} # code in the input file, such as the continuous raster sequences # (CRS) chosen by the RP3 software. The group is available through # {path_hp.get_group}. # # The returned list of contacts {CTS} will have all the contacts # specified in the input file. # return input_data_IMP.read_txt(fname, mp_cont, mp_fill, angle) # SYNTHETIC INPUTS def make_synthetic(dsname, variant, mp_cont, mp_fill): # Returns an internally generated raw data set identified by the given # strings {dsname} and {variant}, whose contour and filling traces use # the specfified move parameters. return input_data_IMP.make_synthetic(dsname, variant, mp_cont, mp_fill) # JOINING FILLERS INTO BLOCKS def create_blocks(OPHS, mp_jump, xdir, ydir, OCRS, initial, split, maxlines, alter): # Assembles the raster fill elements from {OPHS} into blocks, # by several criteria. # # First, each raster is assigned to a group, depending on its # pre-existing assignment and on the parameters {initial, split, and maxlines}. # Then each group is made into a {Block} object. The fillers of the group # are concatenated in several ways, depending on the boolean {alter}, # to produce the various choices of the block. # # (Re)grouping the fillers # # The {initial} parameter is a string that selects an initial grouping # of the fillers. The possible arguments and their meanings are: # # 'original' : the initial grouping is whatever was defined # before calling the procedure. E.g., if the rasters are # read from a ".txt" file produced bt {RP3}, the groups will # be {RP3}'s continuous raster sequences (OCRSs). # # 'single' : all fillers are assigned to a single initial group. # # 'contour' : the fillers are divided into groups based on the innermost # contour path that contains them. Thus there will be one group for # each connected component of the slice (viewed as a polygonal # plane region bounded by the axes of the contours) # that has at least one raster in it. # # 'graph' : the /contact graph/ vertices are the rasters of {OPHS} and # the edges are the contacts whose sides are both in that list. # The rasters will be grouped according to the connected components of # that graph. Note that this is a refinement of the 'contour' # grouping. # # The initial grouping defined by the {initial} parameter will then be modified # by the procedures according to the parameters {single} and {max_lines}. # # Specifically, if {split} is true, the initial groups are split into # maximal sub-groups such that there is exactly one contact between # every two consecutive elements of the same sub-group. In this case # the {initial} options 'single', 'contour', and 'graph' will produce the # same result, and 'original' is likely to do the same. # # In any case, if {max_lines} is a positive integer, the fillers in each # group (initial or split) are sorted by scan-line order and the group # is split into sub-groups such that each sub-group comprises at most # {max_lines} consecutive whole scan-lines. # # In articular, if {split} is true and {maxlines} is 1, each raster # will be a separate group by itself, and {initial} will be # irrelevant. If {split} is false and {max_lines} is 1, each group # defined by {initial} will be split into sub-groups by scanline. # # Turning groups into blocks # # After the rasters are (re)grouped as above, the fillers in each # groups are turned into a {Block} object. # # If a group is contained in a single scan-line, the fillers are # concatenated in the given order (that is, of increasing {xdir} # projection) forming a path {bph}. The block's choices then will be # {bph} and its reverse. # # If a group spans more than one scan-line, the fillers are # conatenated in order of increasing scanline. Two paths {bph0} and # {bph1} are created: one with the fillers in the first scanline # oriented and ordered left to right, and the other with those fillers # oriented and ordered right to left. In each case, if {alter} is # true, the order and orientation are reversed at each subsequent # scanline, otherwise the same order and orientation is used for all # scanlines. The block will then have four choices: th two paths {bph0} and # {bph1}, and their reverses. # # In any case, any gap between two consecutive fillers {oph0} and {oph1} # is bridged by the path {path_hp.connecting_link(oph0,oph1)} if that link # is not {None}, otherwise by a jump with parameters {mp_jump}. # # The procedure also defines the pointers from each choice path to the # owning blocks, accessed through {path_hp.get_block}; and assigns # each block to its innermost containing contour, so that it can be # obtained by {path_hp.get_blocks_in_contour}. # # Some of the contacts between raster elements that are returned by # the procedures that read or create the filler elements may end up # between moves of the same choice of the same block. The client is # expected to check whether those contacts satisfy the cooling time # requirement, and discard them. The pointers from the block choices # to contacts, given by {path_hp.get_contacts}, are NOT defined by # this procedure. return input_data_IMP.create_blocks(OPHS, mp_jump, xdir, ydir, OCRS, initial, split, maxlines, alter) # PRINTOUT def describe(wr, o, BCS, SMS, Delta, maxcalls, mp_jump): # Prints main attributes of the input data to # file {wr} in human-readable form. input_data_IMP.describe(wr, o, BCS, SMS, Delta, maxcalls, mp_jump) # PLOTTING def plot_data_A(fname, OCRS, BCS, CTS, o, wd_ref): # Writes a set of EPS files showing the input dataset # {OCRS,BCS,CTS,o}. Each EPS file shows choice {ip} of each block, for # {ip=0,1,...}, with contacts that are pertinent to that choice. Also # writes the equivalent "jpg", and "png" images. uses standard choices # for colors, decoration, etc. based on the trace width {wd_ref}, # typically the width of solid fill raster lines. # # The files will be called "{fname}_ip{ip}.{ext}" where {ip} is the choice number and {ext} # is "eps", "jpg", or "png". return input_data_IMP.plot_data_A(fname, BCS, CTS, o, wd_ref) def plot_data_B(fname, CRS, BCS, CTS, mp_cont, org): # ??? # Files are "{fname}_ip{NN}.{ext}" where {NN} is the block choice index # and {ext} is "jpg", "eps", and "png". # Returns the bounding box {B} of the data. return input_data_IMP.plot_data_B(fname, CRS, BCS, CTS, mp_cont, org)