From 9d9c3f819d2e5faf25a281d9c914417fa39de3ef Mon Sep 17 00:00:00 2001 From: Juan Pablo Caram Date: Thu, 13 Mar 2014 22:37:59 -0400 Subject: [PATCH] Serialization of ApertureMacro. Change scale, offset and mirror in Gerber to act only upon its resulting geometry, not its source data. --- FlatCAM.py | 15 +- camlib.py | 218 ++++++++++++++++++------- doc/build/.doctrees/environment.pickle | Bin 29823 -> 30384 bytes doc/build/genindex.html | 1 + doc/build/index.html | 2 + doc/build/objects.inv | Bin 1598 -> 1585 bytes doc/build/py-modindex.html | 1 + doc/build/search.html | 1 + doc/build/searchindex.js | 2 +- doc/source/devman.rst | 45 ++++- 10 files changed, 220 insertions(+), 65 deletions(-) diff --git a/FlatCAM.py b/FlatCAM.py index 3f807e0d..18215a57 100644 --- a/FlatCAM.py +++ b/FlatCAM.py @@ -16,6 +16,7 @@ from gi.repository import GLib from gi.repository import GObject import simplejson as json +import matplotlib from matplotlib.figure import Figure from numpy import arange, sin, pi from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas @@ -482,7 +483,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): return self.plot2(self.axes, tooldia=self.options["tooldia"]) - self.app.plotcanvas.auto_adjust_axes() + + #self.app.plotcanvas.auto_adjust_axes() + GLib.idle_add(self.app.plotcanvas.auto_adjust_axes) def convert_units(self, units): factor = CNCjob.convert_units(self, units) @@ -625,7 +628,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): print "WARNING: Did not plot:", str(type(geo)) - self.app.plotcanvas.auto_adjust_axes() + #self.app.plotcanvas.auto_adjust_axes() + GLib.idle_add(self.app.plotcanvas.auto_adjust_axes) ######################################## @@ -1267,13 +1271,16 @@ class App: try: f = open(filename, 'r') except: - print "WARNING: Failed to open project file:", filename + #print "WARNING: Failed to open project file:", filename + self.info("ERROR: Failed to open project file: %s" % filename) return try: d = json.load(f, object_hook=dict2obj) except: - print "WARNING: Failed to parse project file:", filename + #print sys.exc_info() + #print "WARNING: Failed to parse project file:", filename + self.info("ERROR: Failed to parse project file: %s" % filename) f.close() return diff --git a/camlib.py b/camlib.py index 79d2b175..69129c8a 100644 --- a/camlib.py +++ b/camlib.py @@ -192,10 +192,38 @@ class ApertureMacro: def __init__(self, name=None): self.name = name self.raw = "" + + ## These below are recomputed for every aperture + ## definition, in other words, are temporary variables. self.primitives = [] self.locvars = {} self.geometry = None + def to_dict(self): + """ + Returns the object in a serializable form. Only the name and + raw are required. + + :return: Dictionary representing the object. JSON ready. + :rtype: dict + """ + + return { + 'name': self.name, + 'raw': self.raw + } + + def from_dict(self, d): + """ + Populates the object from a serial representation created + with ``self.to_dict()``. + + :param d: Serial representation of an ApertureMacro object. + :return: None + """ + for attr in ['name', 'raw']: + setattr(self, attr, d[attr]) + def parse_content(self): """ Creates numerical lists for all primitives in the aperture @@ -632,7 +660,7 @@ class Gerber (Geometry): # from Geometry. self.ser_attrs += ['int_digits', 'frac_digits', 'apertures', 'paths', 'buffered_paths', 'regions', 'flashes', - 'flash_geometry'] + 'flash_geometry', 'aperture_macros'] #### Parser patterns #### # FS - Format Specification @@ -714,55 +742,74 @@ class Gerber (Geometry): Scales the objects' geometry on the XY plane by a given factor. These are: - * ``apertures`` - * ``paths`` + * ``buffered_paths`` + * ``flash_geometry`` + * ``solid_geometry`` * ``regions`` - * ``flashes`` - Then ``buffered_paths``, ``flash_geometry`` and ``solid_geometry`` - are re-created with ``self.create_geometry()``. + NOTE: + Does not modify the data used to create these elements. If these + are recreated, the scaling will be lost. This behavior was modified + because of the complexity reached in this class. + :param factor: Number by which to scale. :type factor: float :rtype : None """ - ## Apertures - # List of the non-dimension aperture parameters - nonDimensions = ["type", "nVertices", "rotation"] - for apid in self.apertures: - for param in self.apertures[apid]: - if param not in nonDimensions: # All others are dimensions. - print "Tool:", apid, "Parameter:", param - self.apertures[apid][param] *= factor - - ## Paths - for path in self.paths: - path['linestring'] = affinity.scale(path['linestring'], - factor, factor, origin=(0, 0)) - - ## Flashes - for fl in self.flashes: - fl['loc'] = affinity.scale(fl['loc'], factor, factor, origin=(0, 0)) + # ## Apertures + # # List of the non-dimension aperture parameters + # nonDimensions = ["type", "nVertices", "rotation"] + # for apid in self.apertures: + # for param in self.apertures[apid]: + # if param not in nonDimensions: # All others are dimensions. + # print "Tool:", apid, "Parameter:", param + # self.apertures[apid][param] *= factor + # + # ## Paths + # for path in self.paths: + # path['linestring'] = affinity.scale(path['linestring'], + # factor, factor, origin=(0, 0)) + # + # ## Flashes + # for fl in self.flashes: + # fl['loc'] = affinity.scale(fl['loc'], factor, factor, origin=(0, 0)) ## Regions for reg in self.regions: reg['polygon'] = affinity.scale(reg['polygon'], factor, factor, origin=(0, 0)) - # Now buffered_paths, flash_geometry and solid_geometry - self.create_geometry() + ## Flashes + for flash in self.flash_geometry: + flash = affinity.scale(flash, factor, factor, origin=(0, 0)) + + ## Buffered paths + for bp in self.buffered_paths: + bp = affinity.scale(bp, factor, factor, origin=(0, 0)) + + ## solid_geometry ??? + # It's a cascaded union of objects. + self.solid_geometry = affinity.scale(self.solid_geometry, factor, + factor, origin=(0, 0)) + + # # Now buffered_paths, flash_geometry and solid_geometry + # self.create_geometry() def offset(self, vect): """ Offsets the objects' geometry on the XY plane by a given vector. These are: - * ``paths`` + * ``buffered_paths`` + * ``flash_geometry`` + * ``solid_geometry`` * ``regions`` - * ``flashes`` - Then ``buffered_paths``, ``flash_geometry`` and ``solid_geometry`` - are re-created with ``self.create_geometry()``. + NOTE: + Does not modify the data used to create these elements. If these + are recreated, the scaling will be lost. This behavior was modified + because of the complexity reached in this class. :param vect: (x, y) offset vector. :type vect: tuple @@ -771,25 +818,48 @@ class Gerber (Geometry): dx, dy = vect - ## Paths - for path in self.paths: - path['linestring'] = affinity.translate(path['linestring'], - xoff=dx, yoff=dy) - - ## Flashes - for fl in self.flashes: - fl['loc'] = affinity.translate(fl['loc'], xoff=dx, yoff=dy) + # ## Paths + # for path in self.paths: + # path['linestring'] = affinity.translate(path['linestring'], + # xoff=dx, yoff=dy) + # + # ## Flashes + # for fl in self.flashes: + # fl['loc'] = affinity.translate(fl['loc'], xoff=dx, yoff=dy) ## Regions for reg in self.regions: reg['polygon'] = affinity.translate(reg['polygon'], xoff=dx, yoff=dy) - # Now buffered_paths, flash_geometry and solid_geometry - self.create_geometry() + ## Buffered paths + for bp in self.buffered_paths: + bp = affinity.translate(bp, xoff=dx, yoff=dy) + + ## Flash geometry + for fl in self.flash_geometry: + fl = affinity.translate(fl, xoff=dx, yoff=dy) + + ## Solid geometry + self.solid_geometry = affinity.translate(self.solid_geometry, xoff=dx, yoff=dy) + + # # Now buffered_paths, flash_geometry and solid_geometry + # self.create_geometry() def mirror(self, axis, point): """ + Mirrors the object around a specified axis passign through + the given point. What is affected: + + * ``buffered_paths`` + * ``flash_geometry`` + * ``solid_geometry`` + * ``regions`` + + NOTE: + Does not modify the data used to create these elements. If these + are recreated, the scaling will be lost. This behavior was modified + because of the complexity reached in this class. :param axis: "X" or "Y" indicates around which axis to mirror. :type axis: str @@ -801,22 +871,35 @@ class Gerber (Geometry): px, py = point xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis] - ## Paths - for path in self.paths: - path['linestring'] = affinity.scale(path['linestring'], xscale, yscale, - origin=(px, py)) - - ## Flashes - for fl in self.flashes: - fl['loc'] = affinity.scale(fl['loc'], xscale, yscale, origin=(px, py)) + # ## Paths + # for path in self.paths: + # path['linestring'] = affinity.scale(path['linestring'], xscale, yscale, + # origin=(px, py)) + # + # ## Flashes + # for fl in self.flashes: + # fl['loc'] = affinity.scale(fl['loc'], xscale, yscale, origin=(px, py)) ## Regions for reg in self.regions: reg['polygon'] = affinity.scale(reg['polygon'], xscale, yscale, origin=(px, py)) - # Now buffered_paths, flash_geometry and solid_geometry - self.create_geometry() + ## Flashes + for flash in self.flash_geometry: + flash = affinity.scale(flash, xscale, yscale, origin=(px, py)) + + ## Buffered paths + for bp in self.buffered_paths: + bp = affinity.scale(bp, xscale, yscale, origin=(px, py)) + + ## solid_geometry ??? + # It's a cascaded union of objects. + self.solid_geometry = affinity.scale(self.solid_geometry, + xscale, yscale, origin=(px, py)) + + # # Now buffered_paths, flash_geometry and solid_geometry + # self.create_geometry() def fix_regions(self): """ @@ -2266,27 +2349,44 @@ def find_polygon(poly_set, point): return None -def to_dict(geo): +def to_dict(obj): """ Makes a Shapely geometry object into serializeable form. - :param geo: Shapely geometry. - :type geo: BaseGeometry - :return: Dictionary with serializable form if ``geo`` was - BaseGeometry, otherwise returns ``geo``. + :param obj: Shapely geometry. + :type obj: BaseGeometry + :return: Dictionary with serializable form if ``obj`` was + BaseGeometry or ApertureMacro, otherwise returns ``obj``. """ - if isinstance(geo, BaseGeometry): + if isinstance(obj, ApertureMacro): + return { + "__class__": "ApertureMacro", + "__inst__": obj.to_dict() + } + if isinstance(obj, BaseGeometry): return { "__class__": "Shply", - "__inst__": sdumps(geo) + "__inst__": sdumps(obj) } - return geo + return obj def dict2obj(d): + """ + Default deserializer. + + :param d: Serializable dictionary representation of an object + to be reconstructed. + :return: Reconstructed object. + """ if '__class__' in d and '__inst__' in d: - # For now assume all classes are Shapely geometry. - return sloads(d['__inst__']) + if d['__class__'] == "Shply": + return sloads(d['__inst__']) + if d['__class__'] == "ApertureMacro": + am = ApertureMacro() + am.from_dict(d['__inst__']) + return am + return d else: return d diff --git a/doc/build/.doctrees/environment.pickle b/doc/build/.doctrees/environment.pickle index 845703a8d921c53f52c847a5d2797e6739922e7f..7a50aee7f7c8362108ff6adb1e0038e984dc7f9d 100644 GIT binary patch literal 30384 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 literal 29823 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
  • FlatCAM Developer Manual
  • diff --git a/doc/build/index.html b/doc/build/index.html index 1b9a0320..7947f847 100644 --- a/doc/build/index.html +++ b/doc/build/index.html @@ -103,6 +103,7 @@
  • FlatCAM Developer Manual
  • @@ -167,6 +168,7 @@
  • FlatCAM Developer Manual
  • diff --git a/doc/build/objects.inv b/doc/build/objects.inv index 4813174880665682863593dca7648a66dbbac94b..fda81fd9dd0c3890daf6816e65852e094d4bb52b 100644 GIT binary patch delta 1483 zcmV;+1vL7;46zK5cz>l?&2Hm15WeRr47Ar6-5mF}2-;!~+b+-tASiMqGoeV8q?|ZU z-=Ro5vMftO^%BQ2M;y-I_sy`iQW**FJ0Ij%%`4Em$1l6?^w{Pf_J`2wUv@vN>^1DZ z$43thm>Hq-(=3sedf-kRt{0|fdD%Z{!B5`6gW#=J74H7EO@G_{wo8xF+Vt@8*WKg8 zADV~fZ$GY<*7yvU+v?@s^8L52+jq9>@hdP~2qJhUY+KpkO%M)N?!N3eE*oAkm9-rh z);Svmi4ulM&=7#U{KMLoDRX~)Hp!phDsX$@AReXxi>uw~N^ESrTS;jdn#>=-Q-r>C z;6m@<2N!OzmVZE5zqCnGXx~6!(01X(II6n1)x;7)V{EWa+u+I8gLeU1<3GV#&BVc4 z4^&gu>YX`glr_FY&01+-o*$t!Fk0Jtz`sX~#UrGXl7-{>Jd?JsGgMi;*eBT&;FWxp1C=4KTiAQ z2+Lb2Z}AuOd2xuO(0E!+scWk@!b*(G=x&lpK96>tk7RYHA;RgEii@C*L;mrWuwnlE z8_^BZK!38@I)sS;?Um>h18)IrFz-{8E+`n;ow;&Uwl_!)8dj3~eJA59$Tf}>YlHby zk#~a|2CEi?TP`WBa?U!k6MoMiGuCm*@}n^0@}>8I@ptglpzf?bHP$>0!A;Ke2)m9; zW!aJI9!k=DZ{Tf3!|_fF;kcOTb?s5d5)7z%rGF*XaZg+y&rygmuW+J(@io58gwGl) zx>Uv@=5|HG_AP&nAUs4zl=cDND2j2Q;|Sw7+-#9#8Pt~n2G*sD(eY}i9z{5O#)N^W zW4d$G02vX^r>q^)>g~41Ex<^!*4koDNT_+Q3&?BabQMxw2PM&m-eXcVDs99=aH{Ij zBY*cb9AQaJ!HrOo(GQc1sOeJIFn%-Y)OXR_oi!M045SK6)%kvMX!{0ELmeXbD^HPg z;Nfm$u9`p3-I+C5OakkTn#2Loys_iFE&R(n=R~`Sp`|THAyFhZ{BDm^VC zLpDn_5m^Z;3P|Nw%pv?5fgk8JHlUq#fq&?-Nt`8)M7Kh2kUtTC-dQX0T8?v7U)NED zheJ^TclPZ96q0QFt!>-1%jAhnmevlToY0h_G4)C!HU)#2bk3MU6rl`kgk7fLABhw5 zpn=Gdue&3UmLasHA@ZN^OHNxE4GBD19||3i!Woe-Ab4+@Ok9R|mX*ah%V43@=SDO9tqgaE3T)5tpyX!lz`SM zw}JBsZ9TjxBkfz!6etok7_kN##D5i3@lOM-m8knR2?ua3*X35>)nXl(=$J5oT1n4M zWo#$c7|Vlh%S4Uc-YskMp9mijvi{@W`uyN(mPyQ9^mXqfrq1s7!0XusHzKF_^~l->8GU_`UBp-2<% z0%j8Gh{ecK6KY}<>Re;EyhJ~8y=~lj;qldJm~9qaUWnegX#=s;a3arrD(ND>aI`VS&vX*dyB>HPoz delta 1496 zcmV;}1tN)!EWR>488AH4A5RP=;pY$AZUvo(k{>s5M+t=D3K*sk|&vb zeJR=F*dC8f`LfwKq9u`!Ghyq(rZ+)2S$X(=;J7TkVs2|2 zFsyMl8WJrGlb|60dHJWcHB;vP`rajff-Arsg@bsR3M{U6mxpZ}nzJcPDk z`~&>Na_-B~zJE^*xX?Oy;ld@i3C+D<*ljpxcd}yzfkEAb3*&fZ(m{Kd2#p|Njkdv) z-3T87w8sAgYc&%mYdt*%rP2^%T?s4mteEF#$VEtPTMzi}89{l5?xr+j3?I|V2j&rE zA}DLfn^p-w_``sU2r||P+hB0XZwR)k@Wzc*CKUFAY=38)cu;>$q{l81$>u%cxmJ~t zPH9a|m4-WXvsPvX_6_vS!-`(IY;O7d_w%bQj$UvLIXO9G%dO=~PJUUbPsq935Pe|; zo_9M2KM|VG+?=@|r~W$5`Yn{V_?H}rUV+j9Y)9#m*KIr*nWk}YBW3#^DU#mpQ;CUG!UWVdCa8-Zv zR1~th?X~77R*qTBO$FqNf4ybtkVEhHHEsb$l25HIR$d7uZ*>Mijl8r#TI*oF`c2V? z(SKu7RjS*Fhu~DvVno(YxY8Tej`#+b96~yyFk97Pa6 zoShSi^wR5bf47wFQq4>@P((?G{uN7&oqt}lwS5Ptp$t)Y^i1IcS^6BzZwQz zY%B3bN&6{4i?%GI2@j{NdhhJ}&{rfm6nnMYTzc}3Qs&Zop`6f^V9uk`F&Y|q7-`m+ zQG2c#YZZAIG1WgFFH4ZtS2pT$l-9KaI)JaiMc?b?o_Oq;e%=pFq6j%>qkBmb?UbZA^g#Uak%KB5)YDSw-tppW1^0i=A?W9Tq`MbJA=7H9r|VvoyT3qfM{u$xQF|v zFDFBHrI1J7M?Zr@j1Jq)d|H)t*7P;%%ynL+j91GAS2X;uRb(a|Pj+{hN`F%M)Sb4! zPRvB8_8El3{VrUdldxLif=#llLQi z*c7PK!_t+)OcUj51yLlO*VjO~Z`QWhSho~7CQ{|VdscAb1V@?D(upD&-h&6}v)#dj z{)O*re1%1cr5a8c_b+778Bwc`&CH;sq1@U*6C^lY04~FU6_>;Xvc6A<*136NuSril y>0=Jylc>rOIkV4@t22YePassTe2bL6*JOOqh#8%jUM!HMs#>=~+x`azeQ7vFzwzJz diff --git a/doc/build/py-modindex.html b/doc/build/py-modindex.html index 765eb2ff..2a9bea0f 100644 --- a/doc/build/py-modindex.html +++ b/doc/build/py-modindex.html @@ -109,6 +109,7 @@
  • FlatCAM Developer Manual
  • diff --git a/doc/build/search.html b/doc/build/search.html index 4be7b0b0..8896dcbf 100644 --- a/doc/build/search.html +++ b/doc/build/search.html @@ -110,6 +110,7 @@
  • FlatCAM Developer Manual
  • diff --git a/doc/build/searchindex.js b/doc/build/searchindex.js index ec8e1fa1..70284982 100644 --- a/doc/build/searchindex.js +++ b/doc/build/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:42,terms:{represent:2,all:[1,2,3,4],code:[1,2,3],toolpath:3,replot:1,focus:1,follow:3,on_key_over_plot:1,make_outlin:3,whose:[1,4],make_circl:3,get_ev:1,on_options_upd:[1,4],flash:3,gerber:1,program:1,text:[1,3],plot_al:1,geom:3,spec:3,cnc:[1,3],digit:3,sourc:3,everi:3,string:[1,3],far:1,mous:1,"5e6cff":3,obround:3,affect:3,on_cb_plot_toggl:1,toolshap:3,button:1,list:[1,3],iter:[3,4],item:1,vector:[1,2,3],specal:1,vertic:3,round:[1,3],get_radio_valu:1,create_geometri:3,natur:3,dimens:[2,3],resourc:1,zero:3,pass:[1,3],rectangular:3,click:1,append:[2,3],index:0,what:4,load_default:1,new_ax:1,neg:[1,3],current:1,delet:1,clipboard:1,"new":[1,2,4],method:[1,2,3],whatev:1,widget:[1,4],default2zero:3,flatcamgeometri:1,gener:[1,2,3],onli:[1,3],matplotlib:[1,2,3],adjust_ax:1,on_create_aligndril:1,path:[1,3],along:[3,4],do_someth:3,modifi:[1,2,3,4],make_moir:3,valu:[1,3,4],box:[1,3],convert:[2,3],on_file_saveprojectcopi:1,action:1,chang:[1,3,4],on_activate_nam:1,on_options_object2app:1,diamet:3,via:1,primit:3,modul:0,on_fileopengerb:1,filenam:[1,3],ymin:[1,3],select:1,frac_digit:[1,3],plot:[1,2,3],from:[1,2,3,4],describ:3,doubl:1,regist:1,setup_component_editor:1,call:[1,2,3,4],flash_geometri:3,dict:[1,2,3],type:[1,2,3,4],start:[1,3],toggl:1,more:3,on_toolbar_replot:1,on_delet:1,combo:1,on_gerber_generate_cutout:1,parse_fil:3,known:1,hole:1,must:[1,3,4],on_file_openproject:1,none:[1,2,3],left:1,ser_attr:3,work:3,uniqu:1,gtext:3,crosshair_thick:3,can:[1,2,3,4],drill:[2,3],z_move:2,fetch:[2,4],overrid:[2,3],meant:1,polygon2gcod:3,give:3,process:[1,3],share:1,indic:3,stroke:3,minimum:1,tab:[1,4],xmin:[1,3],serial:2,z_cut:2,apertureid:3,alwai:3,surfac:3,end:3,hadler:1,fix_region:3,write:3,fals:3,circular:3,b5ab3a:3,recogn:4,make_polygon:3,after:1,befor:[1,2],plane:3,mai:1,circumscrib:3,data:[1,3],subsequ:1,entry_text:1,correspond:[1,3],element:[3,4],callback:1,"switch":1,maintain:1,allow:3,enter:1,on_fileopenexcellon:1,on_file_saveprojecta:1,parse_cont:3,travel:3,checkbox:1,rotat:3,over:[1,4],through:[1,4],untouch:3,on_excellon_tool_choos:1,paramet:[1,2,3],fit:1,save_project:1,chosen:1,fix:3,gtk:1,set_list_select:1,window:1,html:1,creat:[1,2,3],pcb:1,on_options_app2object:1,main:[1,3],alter:3,on_zoom_out:1,non:3,"float":[1,2,3],"return":[1,2,3],thei:[2,3,4],handl:[1,2],rectangl:3,number:[1,3],"break":3,vect:[2,3],build_list:1,project_filenam:1,choic:1,name:[1,2,3,4],edit:4,separ:[1,3],solid_geometri:3,each:[3,4],found:3,updat:[1,4],gui:[1,2,4],read_form:[1,2],parse_lin:3,on_closewindow:1,replac:3,continu:[1,2],"static":3,connect:1,aperturetyp:3,event:1,out:1,variabl:[1,3],on_eval_upd:1,generate_from_excellon_by_tool:3,content:[0,1],adjust:1,set_current_pag:1,clear_polygon:3,on_scrol:1,flatcamcncjob:1,linear:3,insid:3,written:4,precaut:1,given:[1,2,3],flatcamexcellon:1,base:[1,2],dictionari:[1,2,3],org:1,care:1,file_chooser_act:1,generate_from_geometri:3,thread:1,launch:1,angl:3,success:1,motion:1,turn:1,length:3,notebook:1,place:[1,4],outsid:3,geometri:1,treeselect:1,onto:3,support:3,first:4,origin:[1,3],copper:1,on_zoom_in:1,arrai:3,independ:4,f0e24d:3,restrict:1,saepar:1,done:[1,3,4],overwrit:3,thick:3,open:[1,4],predefin:3,size:[1,3],differ:3,setup_obj_class:1,on_toggle_unit:1,associ:[1,2,3],interact:2,flatcamobj:1,attach:[1,2],circl:3,store:[3,4],editor:1,option:[1,3],ratio:[1,2],tool:[1,3],copi:[1,2,3],specifi:[1,2,3],get_empty_area:3,generate_from_excellon:3,part:[2,3],pars:3,get_bounding_box:3,exposur:3,kind:[1,2,3,4],whenev:1,tree:1,entry_ev:1,structur:3,project:[1,4],str:[1,2,3],macro:3,posit:3,"function":[1,4],thereaft:4,ani:[1,3],compon:1,do_flash:3,raw:3,"_app_":[1,4],have:[1,3],inform:1,self:[1,2,3],note:[1,3],also:3,on_options_object2project:1,build:[1,2],which:[1,2,3,4],event_handl:1,interior:3,on_success:1,singl:3,simplifi:3,buffer:3,previou:1,on_mouse_mov:1,pair:[1,3],alpha:3,segment:3,"class":[1,2,3],set_progress_bar:1,appertur:3,clear:[1,2],later:2,cover:[1,3],on_mouse_move_over_plot:1,populate_objects_combo:1,make_centerlin:3,axi:[1,3],thicken:3,show:1,on_click_over_plot:1,apertur:3,radiu:3,syntax:[1,4],radio:1,corner:[1,3],find:1,crosshair_len:3,on_scale_object:1,new_object:1,slow:3,locat:3,menu:1,configur:[1,2],activ:1,state:1,comboboxtext:1,version:[1,2,3],suppos:4,factor:[1,2,3],elin:3,on_options_combo_chang:1,overwritten:4,hit:1,get:[1,2,4],express:3,nativ:1,on_options_app2project:1,mpl_connect:1,multipolygon:3,bar:1,on_create_mirror:1,coord:3,"default":[1,3,4],to_dict:3,xmax:[1,3],contain:[1,4],comma:3,movement:1,where:[1,3,4],dpi:3,user:[1,2],set:[1,2,3],noth:1,keyboard:1,startup:[1,4],on_cncjob_exportgcod:1,displai:1,"4650bd":3,see:[1,3],result:[1,3],arg:1,transpar:[2,3],close:1,contour:3,statu:1,detect:4,kei:[1,2,3,4],boundari:3,label:1,figur:[1,2],max_r:3,between:1,progress:1,wether:3,attribut:3,accord:3,extend:2,numer:3,complement:3,isol:1,job:[1,3],entir:3,here:1,extent:1,toler:3,auto_adjust_ax:1,popul:[1,3,4],both:3,feedrat:[2,3],rtype:[1,3],options2form:1,alon:3,setup_project_list:1,on_generate_gerber_bounding_box:1,lowerleft:3,whole:[1,3],col:1,obj_dict:2,load:1,cncjob:1,point:[1,3],color:3,on_gerber_generate_noncopp:1,enlarg:3,param:[1,3],respect:2,throughout:1,backend:1,quit:1,becom:[2,3],convert_unit:[2,3],addition:3,been:1,mark:1,pute:1,json:[1,2,4],get_curr:1,toolbar:1,open_project:1,subscrib:1,immedi:1,radio_set:1,gcode:3,imag:1,search:0,gap:3,on_file_savedefault:[1,4],coordin:[1,3],on_options_project2object:1,func:1,present:3,versioncheck:1,inhibit:1,therefor:[1,4],apparamet:3,look:3,align:1,properti:[1,3],pixel:1,dest:1,defin:[1,3],"while":1,setup_ax:2,abov:3,margin:3,region:3,propag:1,layer:1,them:2,equal:3,itself:3,exterior:3,on_fileopengcod:1,"__init__":1,around:[1,3],make_lowerleftlin:3,belong:3,same:[1,4],respresent:3,instanc:1,pad:3,descend:[2,3],tool_toler:3,complet:1,http:1,widget_nam:1,upon:[1,4],alert:1,initi:1,canva:[1,2],implement:2,appropri:[1,3],off:1,center:[1,3],build_ui:2,well:3,inherit:4,without:1,on_file_new:1,thi:[1,2,3,4],choos:1,on_generate_paintarea:1,make_vectorlin:3,rout:1,latest:1,distanc:3,identifi:[3,4],entri:1,isolation_geometri:3,"true":[1,3],flatcamgerb:1,rest:3,shape:3,aspect:[1,2],linestr:3,speed:3,previous:4,cut:[1,3],on_tools_doublesid:1,trigger:1,shortcut:1,add:2,other:[1,3],board:1,save:[1,3,4],pre_pars:3,take:1,gcode_pars:3,format:2,read:[1,2,3,4],on_file_saveproject:1,background:2,press:1,height:3,mod:3,like:1,specif:[1,2,3],ring:3,zoom:1,integ:3,instanci:3,from_dict:3,necessari:1,either:1,exobj:3,on_clear_plot:1,page:[0,1],depend:[1,2,3],int_digit:3,creation:[1,4],back:1,percentag:1,on_zoom_fit:1,radiobutton:1,"export":2,mirror:[1,3],set_form_item:[1,2],on_generate_excellon_cncjob:1,scale:[1,2,3],bottom:1,definit:3,overlap:3,on_update_plot:1,buffer_path:3,unit:[1,2,3],duplic:1,refer:4,machin:3,object:[1,3,4],run:[1,3],usag:3,how:4,offset:[1,2,3],on_toggle_pointbox:1,about:1,actual:[2,3],file_chooser_save_act:1,on_generate_cncjob:1,side:1,degre:3,dialog:1,constructor:1,options_update_ignor:1,make_therm:3,on_about:1,chooser:1,within:3,encod:3,bound:[1,3],excellon:1,loc:3,accordingli:1,ymax:[1,3],wai:[3,4],area:[1,3],outer_dia_outer_r:3,transfer:1,n_vert:3,fast:3,make_geometri:3,width:3,clear_poli:1,handler:1,interfac:1,includ:3,fraction:3,on_canvas_configur:1,on_offset_object:1,on_generate_isol:1,linear2gcod:3,form:[1,2],tupl:[2,3],don:[2,3],line:[1,3],on_entry_eval_activ:1,info:1,made:3,whether:2,access:1,maximum:1,tooldia:[2,3],record:1,limit:1,featur:3,buffered_path:3,evalu:3,"int":3,request:1,dure:3,parser:3,aperture_pars:3,repres:[2,3],plot2:3,on_row_activ:1,exist:2,file:[1,3,4],doe:[1,3],check:1,again:3,aplic:1,polygon:[1,3],titl:1,to_form:2,when:[1,3,4],detail:1,invalid:3,field:1,valid:1,bool:[2,3],gline:3,ignor:[1,3],on_options_project2app:1,read_form_item:[1,2],deseri:[2,3],on_tree_selection_chang:1,draw:[1,3],event_nam:1,eval:1,outdat:1,rule:3,geometr:[2,3],aperture_macro:3,on_filequit:1,scroll:1},objtypes:{"0":"py:module","1":"py:method","2":"py:class","3":"py:staticmethod","4":"py:attribute"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","class","Python class"],"3":["py","staticmethod","Python static method"],"4":["py","attribute","Python attribute"]},filenames:["index","app","flatcamobj","camlib","devman"],titles:["Welcome to FlatCAM’s documentation!","FlatCAM Application","FlatCAM Objects","Camlib","FlatCAM Developer Manual"],objects:{"":{camlib:[3,0,0,"-"],FlatCAM:[2,0,0,"-"]},"camlib.CNCjob":{scale:[3,1,1,""],polygon2gcode:[3,1,1,""],generate_from_excellon_by_tool:[3,1,1,""],linear2gcode:[3,1,1,""],pre_parse:[3,1,1,""],generate_from_excellon:[3,1,1,""],gcode_parse:[3,1,1,""],generate_from_geometry:[3,1,1,""],offset:[3,1,1,""],plot2:[3,1,1,""]},FlatCAM:{PlotCanvas:[1,2,1,""],FlatCAMGeometry:[2,2,1,""],App:[1,2,1,""],FlatCAMObj:[2,2,1,""],FlatCAMExcellon:[2,2,1,""],FlatCAMGerber:[2,2,1,""],FlatCAMCNCjob:[2,2,1,""]},"FlatCAM.FlatCAMGerber":{convert_units:[2,1,1,""]},"camlib.Geometry":{convert_units:[3,1,1,""],scale:[3,1,1,""],to_dict:[3,1,1,""],bounds:[3,1,1,""],get_empty_area:[3,1,1,""],isolation_geometry:[3,1,1,""],from_dict:[3,1,1,""],clear_polygon:[3,1,1,""],offset:[3,1,1,""],size:[3,1,1,""]},"FlatCAM.App":{read_form:[1,1,1,""],on_about:[1,1,1,""],on_tree_selection_changed:[1,1,1,""],on_canvas_configure:[1,1,1,""],on_zoom_in:[1,1,1,""],on_delete:[1,1,1,""],on_toggle_units:[1,1,1,""],on_closewindow:[1,1,1,""],on_click_over_plot:[1,1,1,""],on_row_activated:[1,1,1,""],on_fileopengerber:[1,1,1,""],file_chooser_action:[1,1,1,""],on_zoom_out:[1,1,1,""],on_zoom_fit:[1,1,1,""],on_options_object2app:[1,1,1,""],on_file_savedefaults:[1,1,1,""],plot_all:[1,1,1,""],set_form_item:[1,1,1,""],on_generate_excellon_cncjob:[1,1,1,""],on_generate_isolation:[1,1,1,""],on_key_over_plot:[1,1,1,""],on_offset_object:[1,1,1,""],on_gerber_generate_noncopper:[1,1,1,""],on_scale_object:[1,1,1,""],new_object:[1,1,1,""],on_activate_name:[1,1,1,""],get_eval:[1,1,1,""],on_cb_plot_toggled:[1,1,1,""],on_update_plot:[1,1,1,""],save_project:[1,1,1,""],on_options_object2project:[1,1,1,""],setup_component_editor:[1,1,1,""],get_current:[1,1,1,""],open_project:[1,1,1,""],on_options_update:[1,1,1,""],on_file_new:[1,1,1,""],on_options_app2object:[1,1,1,""],on_options_project2app:[1,1,1,""],read_form_item:[1,1,1,""],versionCheck:[1,1,1,""],on_toolbar_replot:[1,1,1,""],on_entry_eval_activate:[1,1,1,""],on_tools_doublesided:[1,1,1,""],on_options_combo_change:[1,1,1,""],setup_obj_classes:[1,1,1,""],on_file_saveproject:[1,1,1,""],setup_project_list:[1,1,1,""],on_generate_gerber_bounding_box:[1,1,1,""],on_options_project2object:[1,1,1,""],on_eval_update:[1,1,1,""],build_list:[1,1,1,""],on_toggle_pointbox:[1,1,1,""],on_file_saveprojectas:[1,1,1,""],info:[1,1,1,""],on_file_openproject:[1,1,1,""],on_options_app2project:[1,1,1,""],set_progress_bar:[1,1,1,""],on_file_saveprojectcopy:[1,1,1,""],on_create_mirror:[1,1,1,""],file_chooser_save_action:[1,1,1,""],on_excellon_tool_choose:[1,1,1,""],on_generate_cncjob:[1,1,1,""],on_clear_plots:[1,1,1,""],on_mouse_move_over_plot:[1,1,1,""],on_fileopengcode:[1,1,1,""],on_gerber_generate_cutout:[1,1,1,""],load_defaults:[1,1,1,""],populate_objects_combo:[1,1,1,""],on_create_aligndrill:[1,1,1,""],on_generate_paintarea:[1,1,1,""],get_radio_value:[1,1,1,""],on_filequit:[1,1,1,""],on_cncjob_exportgcode:[1,1,1,""],options2form:[1,1,1,""],set_list_selection:[1,1,1,""],on_fileopenexcellon:[1,1,1,""]},"camlib.Gerber":{parse_lines:[3,1,1,""],scale:[3,1,1,""],frac_digits:[3,4,1,""],mirror:[3,1,1,""],aperture_parse:[3,1,1,""],offset:[3,1,1,""],create_geometry:[3,1,1,""],parse_file:[3,1,1,""],do_flashes:[3,1,1,""],buffer_paths:[3,1,1,""],fix_regions:[3,1,1,""],get_bounding_box:[3,1,1,""],int_digits:[3,4,1,""]},"camlib.ApertureMacro":{make_geometry:[3,1,1,""],default2zero:[3,3,1,""],make_vectorline:[3,3,1,""],make_polygon:[3,3,1,""],make_moire:[3,3,1,""],make_outline:[3,3,1,""],make_circle:[3,3,1,""],make_thermal:[3,3,1,""],make_centerline:[3,3,1,""],parse_content:[3,1,1,""],append:[3,1,1,""],make_lowerleftline:[3,3,1,""]},"FlatCAM.FlatCAMGeometry":{plot:[2,1,1,""],scale:[2,1,1,""],offset:[2,1,1,""]},"FlatCAM.PlotCanvas":{on_mouse_move:[1,1,1,""],on_scroll:[1,1,1,""],adjust_axes:[1,1,1,""],clear:[1,1,1,""],zoom:[1,1,1,""],connect:[1,1,1,""],new_axes:[1,1,1,""],auto_adjust_axes:[1,1,1,""],mpl_connect:[1,1,1,""]},camlib:{Excellon:[3,2,1,""],ApertureMacro:[3,2,1,""],Geometry:[3,2,1,""],CNCjob:[3,2,1,""],Gerber:[3,2,1,""]},"camlib.Excellon":{parse_lines:[3,1,1,""],scale:[3,1,1,""],offset:[3,1,1,""],create_geometry:[3,1,1,""],mirror:[3,1,1,""],parse_file:[3,1,1,""]},"FlatCAM.FlatCAMObj":{read_form:[2,1,1,""],plot:[2,1,1,""],serialize:[2,1,1,""],deserialize:[2,1,1,""],build_ui:[2,1,1,""],to_form:[2,1,1,""],setup_axes:[2,1,1,""],set_form_item:[2,1,1,""],read_form_item:[2,1,1,""]}},titleterms:{cncjob:3,flatcamgerb:2,app:1,indic:0,aperturemacro:3,tabl:0,excellon:3,flatcam:[0,1,2,4],flatcamgeometri:2,develop:4,welcom:0,flatcamobj:2,gerber:3,camlib:3,document:0,flatcamcncjob:2,applic:1,option:4,object:2,flatcamexcellon:2,plotcanva:1,manual:4,geometri:3}}) \ No newline at end of file +Search.setIndex({envversion:42,terms:{represent:2,all:[1,2,3,4],code:[1,2,3],toolpath:3,replot:1,focus:1,follow:3,on_key_over_plot:1,make_outlin:3,whose:[1,4],make_circl:3,get_ev:1,on_options_upd:[1,4],flash:3,specif:[1,2,3],gerber:[],program:1,on_click_over_plot:1,plot_al:1,geom:3,spec:3,isinst:4,digit:3,sourc:3,everi:3,string:[1,3],far:1,mous:1,"5e6cff":3,obround:3,untouch:3,on_cb_plot_toggl:1,toolshap:3,button:1,list:[1,3,4],iter:[3,4],item:1,vector:[1,2,3],specal:1,round:[1,3],get_radio_valu:1,create_geometri:3,natur:3,dimens:[2,3],resourc:1,zero:3,pass:[1,3],click:1,append:[2,3],index:0,what:4,new_ax:1,neg:[1,3],current:1,delet:1,clipboard:1,buffer_path:3,"new":[1,2,4],method:[1,2,3,4],whatev:1,widget:[1,4],default2zero:3,flatcamgeometri:[],gener:[1,2,3],onli:[1,3],matplotlib:[1,2,3],adjust_ax:1,on_create_aligndril:1,path:[1,3],along:[3,4],vertic:3,modifi:[1,2,3,4],make_moir:3,valu:[1,3,4],box:[1,3],convert:[2,3,4],new_object:1,on_file_saveprojectcopi:1,action:1,chang:[1,3,4],on_activate_nam:1,on_options_object2app:1,diamet:3,via:1,primit:3,modul:0,on_fileopengerb:1,filenam:[1,3,4],basegeometri:4,ymin:[1,3],select:1,frac_digit:[1,3],plot:[1,2,3],from:[1,2,3,4],describ:3,doubl:1,regist:1,setup_component_editor:1,call:[1,2,3,4],save:[1,3,4],suppos:4,type:[1,2,3,4],toggl:1,more:3,on_toolbar_replot:1,evalu:3,on_delet:1,factor:[1,2,3],on_gerber_generate_cutout:1,parse_fil:3,known:1,hole:1,must:[1,3,4],on_file_openproject:1,none:[1,2,3],ser_attr:[3,4],work:3,uniqu:1,gtext:3,crosshair_thick:3,can:[1,2,3,4],drill:[2,3],z_move:2,fetch:[2,4],def:4,overrid:[2,3],overwritten:4,polygon2gcod:3,give:3,process:[1,3,4],share:1,indic:3,stroke:3,minimum:1,tab:[1,4],xmin:[1,3],hit:1,serial:[],z_cut:2,apertureid:3,alwai:3,surfac:3,end:3,hadler:1,fix_region:3,write:3,fals:3,updat:[1,4],parse_lin:3,recogn:4,make_polygon:3,after:1,befor:[1,2],notebook:1,mai:1,setup_obj_class:1,associ:[1,2,3],becom:[2,3],read:[1,2,3,4],onto:3,correspond:[1,3],element:[3,4],inform:1,"switch":1,maintain:1,allow:3,enter:1,make_therm:3,on_file_saveprojecta:1,travel:3,checkbox:1,rotat:3,over:[1,4],tupl:[2,3],through:[1,4],affect:3,on_excellon_tool_choos:1,paramet:[1,2,3],fit:1,respresent:[3,4],chosen:1,fix:3,gtk:1,"__class__":4,set_list_select:1,window:1,html:1,pcb:1,on_options_app2object:1,main:[1,3],pixel:1,non:[3,4],within:3,"return":[1,2,3,4],thei:[2,3,4],handl:[1,2],rectangl:3,number:[1,3],"break":3,vect:[2,3],build_list:1,project_filenam:1,choic:1,name:[1,2,3,4],edit:4,separ:[1,3],solid_geometri:3,each:[3,4],found:3,circular:3,gui:[1,2,4],read_form:[1,2],b5ab3a:3,on_closewindow:1,replac:3,continu:[1,2],"static":3,connect:1,aperturetyp:3,event:1,out:1,variabl:[1,3],on_eval_upd:1,generate_from_excellon_by_tool:3,content:[0,1],adjust:1,set_current_pag:1,clear_polygon:3,on_scrol:1,flatcamcncjob:[],alter:3,linear:3,insid:3,state:1,precaut:1,differ:3,flatcamexcellon:[],base:[1,2],dictionari:[1,2,3,4],latest:1,org:1,care:1,file_chooser_act:1,generate_from_geometri:3,thread:1,launch:1,angl:3,motion:1,turn:1,length:3,plane:3,place:[1,4],outsid:3,geometri:[],treeselect:1,entry_text:1,n_vert:3,first:4,origin:[1,3],copper:1,on_zoom_in:1,arrai:3,independ:4,f0e24d:3,restrict:1,saepar:1,done:[1,3,4],fast:3,thick:3,open:[1,4],predefin:3,size:[1,3],given:[1,2,3],circumscrib:3,on_toggle_unit:1,data:[1,3],interact:2,flatcamobj:[],attach:[1,2],circl:3,interfac:1,locat:3,store:[3,4],includ:[3,4],option:3,handler:1,tool:[1,3],copi:[1,2,3,4],specifi:[1,2,3,4],get_empty_area:3,generate_from_excellon:3,part:[2,3],pars:3,instanci:3,get_bounding_box:3,exposur:3,kind:[1,2,3,4],whenev:1,tree:1,entry_ev:1,structur:3,project:[1,4],str:[1,2,3],build_ui:2,posit:3,initi:1,thereaft:4,ani:[1,3],do_flash:3,raw:3,inherit:4,have:[1,3],callback:1,self:[1,2,3,4],note:[1,3],also:3,on_options_object2project:1,build:[1,2],which:[1,2,3,4],event_handl:1,interior:3,on_success:1,singl:3,simplifi:3,buffer:3,previou:1,on_mouse_mov:1,pair:[1,3],alpha:3,segment:3,"class":[1,2,3],set_progress_bar:1,appertur:3,clear:[1,2],later:[2,4],cover:[1,3],on_mouse_move_over_plot:1,populate_objects_combo:1,make_centerlin:3,axi:[1,3],width:3,thicken:3,recontruct:4,serializ:4,show:1,text:[1,3,4],apertur:3,radiu:3,syntax:[1,4],radio:1,corner:[1,3],find:1,on_scale_object:1,load_default:1,slow:3,ratio:[1,2],menu:1,configur:[1,2],activ:1,written:4,comboboxtext:1,version:[1,2,3],dict:[1,2,3,4],combo:1,elin:3,on_options_combo_chang:1,meant:1,"__inst__":4,get:[1,2,4],on_entry_eval_activ:1,express:3,nativ:1,made:3,geo:4,mpl_connect:1,requir:4,multipolygon:3,bar:1,on_create_mirror:1,coord:3,whether:2,to_dict:[3,4],xmax:[1,3],contain:[1,4],comma:3,movement:1,where:[1,3,4],dpi:3,set:[1,2,3],dump:4,keyboard:1,startup:[1,4],on_cncjob_exportgcod:1,maximum:1,"4650bd":3,see:[1,3],result:[1,3],arg:1,close:1,contour:3,statu:1,detect:4,extend:2,boundari:3,label:1,getattr:4,max_r:3,between:1,progress:1,previous:4,attribut:[3,4],accord:3,kei:[1,2,3,4],numer:3,complement:3,isol:1,job:[1,3],entir:3,here:1,extent:1,toler:3,auto_adjust_ax:1,popul:[1,3,4],both:3,feedrat:[2,3],rtype:[1,3,4],options2form:1,alon:3,setup_project_list:1,instanc:1,lowerleft:3,whole:[1,3],col:1,obj_dict:2,parse_cont:3,load:[1,4],cncjob:[],figur:[1,2],color:3,format:2,on_gerber_generate_noncopp:1,featur:3,shortcut:1,respect:2,throughout:1,backend:1,quit:1,do_someth:3,convert_unit:[2,3],addition:3,been:1,mark:1,pute:1,json:[1,2,4],get_curr:1,toolbar:1,open_project:[1,4],subscrib:1,immedi:1,radio_set:1,gcode:3,imag:1,search:0,gap:3,on_file_savedefault:[1,4],coordin:[1,3],on_options_project2object:1,func:1,present:3,versioncheck:1,inhibit:1,therefor:[1,4],apparamet:3,look:3,align:1,properti:[1,3],rectangular:3,defin:[1,3],"while":1,setup_ax:2,abov:3,margin:3,region:3,propag:1,layer:1,them:2,equal:3,unit:[1,2,3],itself:3,exterior:3,on_fileopengcod:1,"__init__":1,gcode_pars:3,make_lowerleftlin:3,make:4,belong:3,same:[1,4],save_project:[1,4],shply:4,pad:3,descend:[2,3],tool_toler:3,complet:1,http:1,widget_nam:1,upon:[1,4],alert:1,user:[1,2],canva:[1,2],implement:2,appropri:[1,3],off:1,center:[1,3],macro:3,well:3,"_app_":[1,4],without:1,on_file_new:1,thi:[1,2,3,4],choos:1,on_generate_paintarea:1,make_vectorlin:3,rout:1,left:1,distanc:3,identifi:[3,4],crosshair_len:3,isolation_geometri:3,entri:1,rest:3,shape:[3,4],aspect:[1,2],linestr:3,flatcamgerb:[],speed:3,wether:3,cut:[1,3],on_tools_doublesid:1,point:[1,3],param:[1,3,4],add:2,valid:1,board:1,appli:4,subsequ:1,pre_pars:3,take:[1,4],around:[1,3],transpar:[2,3],dest:1,on_file_saveproject:1,background:2,press:1,height:3,mod:3,like:1,success:1,ring:3,zoom:1,integ:3,noth:1,from_dict:3,necessari:1,either:1,exobj:3,on_clear_plot:1,page:[0,1],depend:[1,2,3],encount:4,int_digit:3,creation:[1,4],back:1,percentag:1,on_zoom_fit:1,radiobutton:1,"export":2,mirror:[1,3],set_form_item:[1,2],on_generate_excellon_cncjob:1,scale:[1,2,3],bottom:1,definit:3,overlap:3,on_update_plot:1,flash_geometri:3,cnc:[1,3],duplic:1,refer:4,machin:3,object:3,run:[1,3],usag:3,how:4,offset:[1,2,3],on_toggle_pointbox:1,about:1,actual:[2,3],file_chooser_save_act:1,on_generate_cncjob:1,side:1,degre:3,dialog:1,constructor:1,options_update_ignor:1,on_fileopenexcellon:1,on_about:1,chooser:1,"float":[1,2,3],encod:[3,4],bound:[1,3],excellon:[],compon:1,accordingli:1,ymax:[1,3],wai:[3,4],area:[1,3],outer_dia_outer_r:3,transfer:1,support:3,overwrit:3,make_geometri:3,start:[1,3],clear_poli:1,trigger:1,sdump:4,editor:1,fraction:3,on_canvas_configur:1,"function":[1,4],on_generate_isol:1,linear2gcod:3,form:[1,2,4],on_zoom_out:1,on_offset_object:1,don:[2,3],line:[1,3],"true":[1,3],loc:3,info:1,on_options_app2project:1,attr:4,on_generate_gerber_bounding_box:1,"default":[1,3,4],access:1,displai:1,tooldia:[2,3],record:1,limit:1,otherwis:4,enlarg:3,buffered_path:3,creat:[1,2,3,4],"int":3,request:1,dure:3,parser:3,aperture_pars:3,repres:[2,3],plot2:3,on_row_activ:1,exist:2,file:[1,3,4],doe:[1,3],check:1,again:3,aplic:1,polygon:[1,3],titl:1,to_form:2,when:[1,3,4],detail:1,invalid:3,field:1,other:[1,3],bool:[2,3],gline:3,geometr:[2,3],on_options_project2app:1,read_form_item:[1,2],deseri:[2,3],on_tree_selection_chang:1,draw:[1,3],event_nam:1,eval:1,outdat:1,rule:3,ignor:[1,3],aperture_macro:3,on_filequit:1,scroll:1},objtypes:{"0":"py:module","1":"py:method","2":"py:class","3":"py:staticmethod","4":"py:attribute"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","class","Python class"],"3":["py","staticmethod","Python static method"],"4":["py","attribute","Python attribute"]},filenames:["index","app","flatcamobj","camlib","devman"],titles:["Welcome to FlatCAM’s documentation!","FlatCAM Application","FlatCAM Objects","Camlib","FlatCAM Developer Manual"],objects:{"":{camlib:[3,0,0,"-"],FlatCAM:[2,0,0,"-"]},"camlib.CNCjob":{scale:[3,1,1,""],polygon2gcode:[3,1,1,""],generate_from_excellon_by_tool:[3,1,1,""],linear2gcode:[3,1,1,""],pre_parse:[3,1,1,""],generate_from_excellon:[3,1,1,""],gcode_parse:[3,1,1,""],generate_from_geometry:[3,1,1,""],offset:[3,1,1,""],plot2:[3,1,1,""]},FlatCAM:{PlotCanvas:[1,2,1,""],FlatCAMGeometry:[2,2,1,""],App:[1,2,1,""],FlatCAMObj:[2,2,1,""],FlatCAMExcellon:[2,2,1,""],FlatCAMGerber:[2,2,1,""],FlatCAMCNCjob:[2,2,1,""]},"FlatCAM.FlatCAMGerber":{convert_units:[2,1,1,""]},"camlib.Geometry":{convert_units:[3,1,1,""],scale:[3,1,1,""],to_dict:[3,1,1,""],bounds:[3,1,1,""],get_empty_area:[3,1,1,""],isolation_geometry:[3,1,1,""],from_dict:[3,1,1,""],clear_polygon:[3,1,1,""],offset:[3,1,1,""],size:[3,1,1,""]},"FlatCAM.App":{on_options_object2app:[1,1,1,""],on_about:[1,1,1,""],on_tree_selection_changed:[1,1,1,""],on_canvas_configure:[1,1,1,""],on_zoom_in:[1,1,1,""],on_delete:[1,1,1,""],on_toggle_units:[1,1,1,""],on_closewindow:[1,1,1,""],on_click_over_plot:[1,1,1,""],on_row_activated:[1,1,1,""],on_fileopengerber:[1,1,1,""],file_chooser_action:[1,1,1,""],on_zoom_out:[1,1,1,""],on_zoom_fit:[1,1,1,""],on_file_savedefaults:[1,1,1,""],on_generate_excellon_cncjob:[1,1,1,""],set_form_item:[1,1,1,""],plot_all:[1,1,1,""],read_form:[1,1,1,""],on_generate_isolation:[1,1,1,""],on_key_over_plot:[1,1,1,""],on_offset_object:[1,1,1,""],on_gerber_generate_noncopper:[1,1,1,""],on_fileopengcode:[1,1,1,""],new_object:[1,1,1,""],on_activate_name:[1,1,1,""],get_eval:[1,1,1,""],on_cb_plot_toggled:[1,1,1,""],on_update_plot:[1,1,1,""],save_project:[1,1,1,""],on_options_object2project:[1,1,1,""],setup_component_editor:[1,1,1,""],get_current:[1,1,1,""],open_project:[1,1,1,""],on_options_update:[1,1,1,""],on_file_new:[1,1,1,""],on_options_app2object:[1,1,1,""],on_options_project2app:[1,1,1,""],read_form_item:[1,1,1,""],versionCheck:[1,1,1,""],on_toolbar_replot:[1,1,1,""],on_entry_eval_activate:[1,1,1,""],on_scale_object:[1,1,1,""],on_options_combo_change:[1,1,1,""],setup_obj_classes:[1,1,1,""],on_file_saveproject:[1,1,1,""],setup_project_list:[1,1,1,""],on_generate_gerber_bounding_box:[1,1,1,""],on_options_project2object:[1,1,1,""],on_eval_update:[1,1,1,""],build_list:[1,1,1,""],on_toggle_pointbox:[1,1,1,""],on_file_saveprojectas:[1,1,1,""],info:[1,1,1,""],on_file_openproject:[1,1,1,""],on_options_app2project:[1,1,1,""],set_progress_bar:[1,1,1,""],on_file_saveprojectcopy:[1,1,1,""],on_create_mirror:[1,1,1,""],file_chooser_save_action:[1,1,1,""],on_excellon_tool_choose:[1,1,1,""],on_generate_cncjob:[1,1,1,""],on_clear_plots:[1,1,1,""],on_mouse_move_over_plot:[1,1,1,""],on_tools_doublesided:[1,1,1,""],on_gerber_generate_cutout:[1,1,1,""],load_defaults:[1,1,1,""],populate_objects_combo:[1,1,1,""],on_create_aligndrill:[1,1,1,""],on_generate_paintarea:[1,1,1,""],get_radio_value:[1,1,1,""],on_filequit:[1,1,1,""],on_cncjob_exportgcode:[1,1,1,""],options2form:[1,1,1,""],set_list_selection:[1,1,1,""],on_fileopenexcellon:[1,1,1,""]},"camlib.Gerber":{parse_lines:[3,1,1,""],scale:[3,1,1,""],frac_digits:[3,4,1,""],buffer_paths:[3,1,1,""],aperture_parse:[3,1,1,""],offset:[3,1,1,""],create_geometry:[3,1,1,""],parse_file:[3,1,1,""],do_flashes:[3,1,1,""],mirror:[3,1,1,""],fix_regions:[3,1,1,""],get_bounding_box:[3,1,1,""],int_digits:[3,4,1,""]},"camlib.ApertureMacro":{make_geometry:[3,1,1,""],default2zero:[3,3,1,""],make_vectorline:[3,3,1,""],make_polygon:[3,3,1,""],make_moire:[3,3,1,""],make_outline:[3,3,1,""],make_circle:[3,3,1,""],parse_content:[3,1,1,""],make_centerline:[3,3,1,""],make_thermal:[3,3,1,""],append:[3,1,1,""],make_lowerleftline:[3,3,1,""]},"FlatCAM.FlatCAMGeometry":{plot:[2,1,1,""],scale:[2,1,1,""],offset:[2,1,1,""]},"FlatCAM.PlotCanvas":{on_mouse_move:[1,1,1,""],on_scroll:[1,1,1,""],adjust_axes:[1,1,1,""],clear:[1,1,1,""],zoom:[1,1,1,""],connect:[1,1,1,""],new_axes:[1,1,1,""],auto_adjust_axes:[1,1,1,""],mpl_connect:[1,1,1,""]},camlib:{Excellon:[3,2,1,""],ApertureMacro:[3,2,1,""],Geometry:[3,2,1,""],CNCjob:[3,2,1,""],Gerber:[3,2,1,""]},"camlib.Excellon":{parse_lines:[3,1,1,""],scale:[3,1,1,""],offset:[3,1,1,""],create_geometry:[3,1,1,""],mirror:[3,1,1,""],parse_file:[3,1,1,""]},"FlatCAM.FlatCAMObj":{read_form:[2,1,1,""],plot:[2,1,1,""],serialize:[2,1,1,""],deserialize:[2,1,1,""],build_ui:[2,1,1,""],to_form:[2,1,1,""],setup_axes:[2,1,1,""],set_form_item:[2,1,1,""],read_form_item:[2,1,1,""]}},titleterms:{cncjob:3,flatcamgerb:2,app:1,indic:0,aperturemacro:3,tabl:0,excellon:3,serial:4,option:4,flatcamgeometri:2,develop:4,welcom:0,flatcamobj:2,gerber:3,camlib:3,document:0,flatcamcncjob:2,applic:1,flatcam:[0,1,2,4],object:2,flatcamexcellon:2,plotcanva:1,manual:4,geometri:3}}) \ No newline at end of file diff --git a/doc/source/devman.rst b/doc/source/devman.rst index 0edff32b..1693620e 100644 --- a/doc/source/devman.rst +++ b/doc/source/devman.rst @@ -12,4 +12,47 @@ There are **Application Defaults**, **Project Options** and **Object Options** i **Object Options** for each object are inherited from Project Options upon creation of each new object. They can be modified independently from the Project's options thereafter through the UI, where the widget containing the option is identified by name: ``type + kind + "_" + option``. They are stored in ``object.options``. They are saved along the Project options when saving the project. -The syntax of UI widget names contain a ``type``, which identifies what *type of widget* it is and how its value is supposed to be fetched, and a ``kind``, which refer to what *kind of FlatCAM Object* it is for. \ No newline at end of file +The syntax of UI widget names contain a ``type``, which identifies what *type of widget* it is and how its value is supposed to be fetched, and a ``kind``, which refer to what *kind of FlatCAM Object* it is for. + +Serialization +~~~~~~~~~~~~~ + +Serialization refers to converting objects into a form that can be saved in a text file and recontructing objects from a text file. + +Saving and loading projects require serialization. These are done in ``App.save_project(filename)`` and ``App.open_project(filename)``. + +Serialization in FlatCAM takes 2 forms. The first is calling objects' ``to_dict()`` method, which is inherited from ``Geometry.to_dict()``:: + + def to_dict(self): + """ + Returns a respresentation of the object as a dictionary. + Attributes to include are listed in ``self.ser_attrs``. + + :return: A dictionary-encoded copy of the object. + :rtype: dict + """ + d = {} + for attr in self.ser_attrs: + d[attr] = getattr(self, attr) + return d + + +This creates a dictionary with attributes specified in the object's ``ser_attrs`` list. If these are not in a serialized form, they will be processed later by the function ``to_dict()``:: + + def to_dict(geo): + """ + Makes a Shapely geometry object into serializeable form. + + :param geo: Shapely geometry. + :type geo: BaseGeometry + :return: Dictionary with serializable form if ``geo`` was + BaseGeometry, otherwise returns ``geo``. + """ + if isinstance(geo, BaseGeometry): + return { + "__class__": "Shply", + "__inst__": sdumps(geo) + } + return geo + +This is used in ``json.dump(d, f, default=to_dict)`` and is applied to objects that json encounters to be in a non-serialized form. \ No newline at end of file