• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Allegro X Scripting - Skill
  3. Extract areas on the FPCB that do not contain arcs.

Stats

  • Replies 8
  • Subscribers 19
  • Views 455
  • Members are here 0
More Content

Extract areas on the FPCB that do not contain arcs.

SG20260713408
SG20260713408 11 days ago

When designing an FPCB (Flexible Printed Circuit Board), corners are often rounded using arcs.

This script extracts the coordinates of connection points between cline segments where no arc has been generated.
In other words, assuming that all corners should be rounded with arcs, it identifies the locations where arcs are missing.
Therefore, you can verify the design by running the test after applying arcs to all corners.

GoodBye~~

axlCmdRegister("find_napoc" 'Find_No_Arc_Point_Of_Clines ?cmdType "interactive")

procedure(Find_No_Arc_Point_Of_Clines()

let((theta_lists check_list check_lists cline_seg_count all_cline_seg_count
sel_nets sel_net_name sel_net_branches sel_net_branches_childrens pin_via_dbs cline_dbs
cline_db_segments first_seg_in_pin_via_value layer first_startend
first_start_xy first_end_xy first_find_pin_via_db first_find_pin_via_db_poly first_start_xy_in_db_result first_end_xy_in_db_result
last_startend last_start_xy last_end_xy last_find_pin_via_db last_find_pin_via_db_poly
segment_objtype segment_layer segment_start_end_xy segment_start_xy segment_start_x segment_start_y
segment_end_xy segment_end_x segment_end_y delta_x delta_y
theta theta_lists seg_start_xy_in_first_db_result seg_start_xy_in_last_db_result)

theta_lists = list(nil)

check_lists = list()

axlClearSelSet()

sel_nets = axlDBGetDesign() -> nets

foreach(sel_net sel_nets

sel_net_name = sel_net -> name

sel_net_branches = sel_net -> branches

when(sel_net_branches

foreach(sel_net_branche sel_net_branches

sel_net_branches_childrens = sel_net_branche -> children

pin_via_dbs = setof(db sel_net_branches_childrens db -> objType == "pin" || db -> objType == "via")

cline_dbs = setof(db sel_net_branches_childrens db -> objType == "path")

when(cline_dbs

foreach(cline_db cline_dbs

cline_db_segments = cline_db -> segments

when(cline_db_segments

cline_db_segments_length = length(cline_db_segments)

cline_seg_count = 0

all_cline_seg_count = 0

first_seg_in_pin_via_value = nil

layer = car(cline_db_segments) -> layer

first_startend = car(cline_db_segments) -> startEnd

first_start_xy = car(first_startend)

first_end_xy = cadr(first_startend)

first_find_pin_via_db = car(setof(db pin_via_dbs axlGeoPointsEqual(db -> xy first_start_xy)))

if(first_find_pin_via_db then

first_find_pin_via_db_poly = car(axlPolyFromDB(first_find_pin_via_db ?layer layer ?padType 'REGULAR))

first_start_xy_in_db_result = axlGeoPointInShape(first_start_xy first_find_pin_via_db_poly)

first_end_xy_in_db_result = axlGeoPointInShape(first_end_xy first_find_pin_via_db_poly)

when(first_start_xy_in_db_result && first_end_xy_in_db_result first_seg_in_pin_via_value = t)

else

first_find_pin_via_db_poly = nil

first_seg_in_pin_via_value = nil

)

last_startend = lastelem(cline_db_segments) -> startEnd

last_start_xy = car(last_startend)

last_end_xy = cadr(last_startend)

last_find_pin_via_db = car(setof(db pin_via_dbs axlGeoPointsEqual(db -> xy last_end_xy)))

if(last_find_pin_via_db then

last_find_pin_via_db_poly = car(axlPolyFromDB(last_find_pin_via_db ?layer layer ?padType 'REGULAR))

else

last_find_pin_via_db_poly = nil

)

foreach(segment cline_db_segments

cline_seg_count = ++cline_seg_count

all_cline_seg_count = ++all_cline_seg_count

segment_objtype = segment -> objType

segment_layer = cadr(parseString(segment -> layer "/"))

segment_start_end_xy = segment -> startEnd

segment_start_xy = car(segment_start_end_xy)

segment_start_x = car(segment_start_xy)

segment_start_y = cadr(segment_start_xy)

segment_end_xy = cadr(segment_start_end_xy)

segment_end_x = car(segment_end_xy)

segment_end_y = cadr(segment_end_xy)

delta_x = segment_start_x - segment_end_x

delta_y = segment_start_y - segment_end_y

if(oddp(cline_seg_count) then

theta = axlRadToDeg(atan2(delta_y delta_x))

theta_lists = cons(theta theta_lists)

when(all_cline_seg_count == 1 && first_seg_in_pin_via_value cline_seg_count = 1)

when(segment_objtype == "arc" cline_seg_count = 0)

)

if(zerop(cline_seg_count) && evenp(cline_seg_count) then

theta = axlRadToDeg(atan2(delta_y delta_x))

theta_lists = cons(theta theta_lists)

else

when(!zerop(cline_seg_count) && evenp(cline_seg_count)

seg_start_xy_in_first_db_result = axlGeoPointInShape(segment_start_xy first_find_pin_via_db_poly)

;;seg_end_xy_in_first_db_result = axlGeoPointInShape(segment_end_xy first_find_pin_via_db_poly)

seg_start_xy_in_last_db_result = axlGeoPointInShape(segment_start_xy last_find_pin_via_db_poly)

;;seg_end_xy_in_last_db_result = axlGeoPointInShape(segment_end_xy last_find_pin_via_db_poly)

before_theta = car(theta_lists)

if(segment_objtype != "arc" then

theta = axlRadToDeg(atan2(delta_y delta_x))

if(axlGeoEqual(before_theta theta) then

cline_seg_count = 1

theta_lists = cons(theta theta_lists)

else

if(seg_start_xy_in_first_db_result || seg_start_xy_in_last_db_result then

cline_seg_count = 1

theta_lists = cons(theta theta_lists)

else

check_list = list(segment_layer segment_start_xy sel_net_name)

check_lists = cons(check_list check_lists)

cline_seg_count = 1

theta_lists = cons(theta theta_lists)

)

)

else

cline_seg_count = 0

)

)

)

theta_lists = list(car(theta_lists))

)

)

)

)

)

)

)

check_lists = sortcar(check_lists 'axlStrcmpAlpNum)

if(zerop(length(check_lists)) then

;;printf("### Error Count = 0 ###\n")

axlUIConfirm("Error Count Zero(0)" 'info)

else

Create_Find_No_Arc_Point_Of_Clines_log_File(check_lists)

)

)

)


procedure(Create_Find_No_Arc_Point_Of_Clines_log_File(checking_result_infor_lists)

let((total_all_error_count Date)

total_all_error_count = 0
Date = (getCurrentTime)
Date = parseString(Date " ")
Date = strcat(nth(3 Date) " " nth(0 Date) " " nth(1 Date) " " nth(2 Date))

Find_No_Arc_Point_Of_Clines_Log_File = outfile("./Find_No_Arc_Point_Of_Clines.log" "w")

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "\nDATE : %s\n" Date)

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "\nSyntax : Layer, Point_XY, Net_Name\n")

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "\n=========================================================================\n")

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "\n ## REPORT OF NO ARC BETWEEN TWO CLINE SEGS ##\n\n")

foreach(checking_result_infor_list checking_result_infor_lists

total_all_error_count = ++total_all_error_count

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "%d.%s, %L, %s\n" total_all_error_count car(checking_result_infor_list) cadr(checking_result_infor_list) caddr(checking_result_infor_list))

)

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "\n=========================================================================\n\n")

fprintf(Find_No_Arc_Point_Of_Clines_Log_File "Total Error Count = %d ea.\n" total_all_error_count)

close(Find_No_Arc_Point_Of_Clines_Log_File)

axlShell("viewlog ./Find_No_Arc_Point_Of_Clines.log")

)

)

  • Sign in to reply
  • Cancel

Top Replies

  • Hoangkhoipcb
    Hoangkhoipcb 5 days ago +1
    Hi SG20260713408 , I tested your code, and it works well for me. I've made a shorter version of the code for you to reference. axlCmdRegister ( "create_arc_chk" 'create_arc_chk ) ( defun create_arc_chk…
  • Elecguy
    Elecguy 8 days ago

    Interesting. But with no comments, no header, no instructions for the type of database it works on ... difficult to test

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • SG20260713408
    SG20260713408 8 days ago in reply to Elecguy

    I apologize.
    When designing an FPCB (Flexible Printed Circuit Board), corners are often rounded using arcs.
    This script extracts the coordinates of connection points between cline segments where no arc has been generated.
    In other words, assuming that all corners should be rounded with arcs, it identifies the locations where arcs are missing.
    Therefore, you can verify the design by running the test after applying arcs to all corners.

    thank you

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Hoangkhoipcb
    Hoangkhoipcb 5 days ago

    Hi SG20260713408,

    I tested your code, and it works well for me.
    I've made a shorter version of the code for you to reference.

    axlCmdRegister("create_arc_chk" 'create_arc_chk)
    (defun create_arc_chk ()
        (let ()
            prog(()
                axlSetFindFilter(?enabled '("noall" "CLINES" "INVISIBLE") ?onButtons '("all"))
                axlAddSelectAll()
                clines = axlGetSelSet()
                axlClearSelSet()
                tmp_list = nil
                seg_list = nil
                Out_file = outfile("create_arc_chk.log" "w")
                fprintf(Out_file "%-5s %-7s %-10s %s\n" "No" "Angle" "Layer" "Location" )
                foreach(cline clines
                    segs = cline->segments
                    foreach(seg segs
                        if(length(member(seg segs)) > 1 then
                            next_seg = cadr(member(seg segs))
                            if(seg->xy == nil && next_seg->xy == nil then
                                ol = axl_ol_ol2(seg->startEnd next_seg->startEnd)
                                if(member(car(ol) tmp_list) == nil then
                                    angle = abs(axlRadToDeg(axlGeoAngleBetweenLines(seg->startEnd next_seg->startEnd)))
                                    if(axlGeoEqual(angle 0.0) || axlGeoEqual(angle 180.0) then
                                    else
                                        push(car(ol) tmp_list)
                                        fprintf(Out_file "%-5d %-7.2f %-10s %L\n" length(tmp_list) angle cadr(parseString(seg->layer "/")) car(ol) )
                                        push(seg seg_list)
                                        push(next_seg seg_list)
                                    )
                                )
                            )
                        )
                    )
                )
                close(Out_file)
                if(length(tmp_list) > 0 then
                    axlHighlightObject(seg_list)
                    axlUIViewFileCreate("create_arc_chk.log" "Arc Segments Check" nil)
                    printf("Errors : %d\n" length(tmp_list))
                )
            )
        )
    )
    BR,

    HoangKhoi
    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • SG20260713408
    SG20260713408 4 days ago in reply to Hoangkhoipcb

    Thanks, Hoangkhoipcb!
    I appreciate you sharing such concise code.
    I’m still studying to fully understand it,
    but I’ll take your code to heart; it will certainly help me think about writing code more concisely or elegantly.
    I’d love to ask for your email address,
    but given the nature of this community, I feel it’s not the right place for private conversations.
    I may lack expertise myself, but I notice that
    high-level script developers aren't providing answers here.

    Here are my personal thoughts on the code:

    1. I’m not sure why the "prog" function was used.

    2. There is no exception handling.
    - If a cline segment (or cline) is connected to a via, pin, or shape, there is no need to extract the point.

    3. The order of the results was determined for the sake of the next step.
    - The angle of the result doesn't matter; the designer just needs to be able to verify the result.
    (Though it would be useful for debugging purposes.)
    - If layers are mixed, unnecessary screen control operations are repeated.

    4. When I was a beginner, I used to put every function into a single block,
    but as the code grew longer, it became difficult to review or maintain, so I separated the log file generation.
    Ultimately, I decided to create separate functions for each specific task.

    thank you~~

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Hoangkhoipcb
    Hoangkhoipcb 4 days ago in reply to SG20260713408

    Hi SG,

    Thank you very much for your thoughtful feedback! I really appreciate your comments.

    1. I use prog mainly out of habit. When validating multiple input parameters, I prefer to exit immediately if something is invalid.

    2. Exception handling depends on the design requirements. In my case, I intentionally don't allow those cases to be skipped.

    3. This SKILL was written quickly to check a design with around 50,000 clines on a single layer, so I allow the user to select the layer to process and saved time .

    4. I agree with you about separating functions. I would also suggest keeping the code as clear and concise as possible, including using shorter and more meaningful variable names where appropriate. This can make the code easier to read, review, and maintain.

    I hope you continue improving your SKILL development skills in future.

    If you'd like to contact me, hoangkhoipcb_@_gmail_com

    BR.


    HoangKhoi

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
>
Cadence Guidelines

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2026 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information